From 65e4c1dd781876374734f4520a9f51b6aae0cf79 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 11 Nov 2020 13:45:20 -0500
Subject: fixes to centering of documents in ContentFittingDocumentView.  
 fixed display of document title in tree view when it was alrady rendered in
 the tree view.

---
 src/client/views/PropertiesView.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'src/client/views/PropertiesView.tsx')

diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index fad2f5284..17cfb5a5a 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -273,7 +273,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                     backgroundColor={this.props.backgroundColor}
                     fitToBox={true}
                     FreezeDimensions={true}
-                    dontCenter={true}
+                    dontCenter={"y"}
                     NativeWidth={layoutDoc.type === DocumentType.RTF ? this.rtfWidth : undefined}
                     NativeHeight={layoutDoc.type === DocumentType.RTF ? this.rtfHeight : undefined}
                     PanelWidth={panelWidth}
-- 
cgit v1.2.3-70-g09d2


From 6862403368f752ad44c9e64bfdbcb38d2c32287c Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sun, 22 Nov 2020 10:34:14 -0500
Subject: converted backgroundColor prop to a more general styleProvider.

---
 src/client/views/GestureOverlay.tsx                |  2 +-
 src/client/views/MainView.tsx                      | 56 ++-----------
 src/client/views/OverlayView.tsx                   |  2 +-
 src/client/views/Palette.tsx                       |  2 +-
 src/client/views/PropertiesView.tsx                |  4 +-
 .../views/collections/CollectionCarouselView.tsx   |  2 +-
 .../views/collections/CollectionLinearView.tsx     |  2 +-
 .../views/collections/CollectionStackingView.tsx   |  2 +-
 .../views/collections/CollectionTreeView.tsx       |  6 +-
 src/client/views/collections/CollectionView.tsx    |  4 +-
 src/client/views/collections/TabDocView.tsx        | 95 ++++++++++++++++++++--
 src/client/views/collections/TreeView.tsx          |  6 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  7 +-
 .../collectionGrid/CollectionGridView.tsx          |  2 +-
 .../CollectionMulticolumnView.tsx                  |  2 +-
 .../CollectionMultirowView.tsx                     |  2 +-
 src/client/views/nodes/AudioBox.tsx                |  2 +-
 .../views/nodes/CollectionFreeFormDocumentView.tsx | 12 +--
 .../views/nodes/ContentFittingDocumentView.tsx     |  2 +-
 src/client/views/nodes/DocHolderBox.tsx            |  6 +-
 src/client/views/nodes/DocumentView.tsx            | 48 ++---------
 src/client/views/nodes/FieldView.tsx               |  2 +-
 src/client/views/nodes/FilterBox.tsx               |  2 +-
 src/client/views/nodes/FontIconBox.tsx             |  2 +-
 src/client/views/nodes/LinkBox.tsx                 |  2 +-
 src/client/views/nodes/LinkDocPreview.tsx          |  4 +-
 .../views/nodes/formattedText/DashDocView.tsx      |  2 +-
 .../views/nodes/formattedText/RichTextSchema.tsx   |  2 +-
 .../views/presentationview/PresElementBox.tsx      |  4 +-
 src/fields/Doc.ts                                  |  1 +
 src/mobile/AudioUpload.tsx                         |  2 +-
 src/mobile/MobileInterface.tsx                     |  2 +-
 32 files changed, 149 insertions(+), 142 deletions(-)

(limited to 'src/client/views/PropertiesView.tsx')

diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index ffa089af1..35dedf016 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -901,7 +901,7 @@ export class GestureOverlay extends Touchable {
                 PanelWidth={this.return300}
                 PanelHeight={this.return300}
                 renderDepth={0}
-                backgroundColor={returnEmptyString}
+                styleProvider={returnEmptyString}
                 focus={emptyFunction}
                 parentActive={returnTrue}
                 whenActiveChanged={emptyFunction}
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 6947dd3cd..ce526f842 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -16,7 +16,6 @@ import { emptyFunction, emptyPath, returnEmptyDoclist, returnEmptyFilter, return
 import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager';
 import { DocServer } from '../DocServer';
 import { Docs } from '../documents/Documents';
-import { DocumentType } from '../documents/DocumentTypes';
 import { CurrentUserUtils } from '../util/CurrentUserUtils';
 import { DocumentManager } from '../util/DocumentManager';
 import { GroupManager } from '../util/GroupManager';
@@ -59,8 +58,8 @@ import { SearchBox } from './search/SearchBox';
 import { TraceMobx } from '../../fields/util';
 import { SelectionManager } from '../util/SelectionManager';
 import { UndoManager } from '../util/UndoManager';
+import { TabDocView } from './collections/TabDocView';
 const _global = (window /* browser */ || global /* node */) as any;
-import Color = require('color');
 
 @observer
 export class MainView extends React.Component {
@@ -230,46 +229,6 @@ export class MainView extends React.Component {
     getPHeight = () => this._panelHeight;
     getContentsHeight = () => this._panelHeight - Number(SEARCH_PANEL_HEIGHT.replace("px", ""));
 
-    defaultBackgroundColors = (doc: Opt<Doc>, renderDepth: number, layerProvider?: (doc: Doc, assign?: boolean) => boolean) => {
-        let docColor = StrCast(doc?._backgroundColor, StrCast(doc?.backgroundColor));
-        if (!docColor) {
-            if (this.darkScheme) {
-                switch (doc?.type) {
-                    case DocumentType.PRESELEMENT: docColor = "dimgrey"; break;
-                    case DocumentType.PRES: docColor = "#3e3e3e"; break;
-                    case DocumentType.FONTICON: docColor = "black"; break;
-                    case DocumentType.RTF || DocumentType.LABEL || DocumentType.BUTTON: docColor = "#2d2d2d"; break;
-                    case DocumentType.LINK:
-                    case DocumentType.COL:
-                        docColor = Doc.IsSystem(doc) ? "rgb(62,62,62)" : StrCast(renderDepth > 0 ? Doc.UserDoc().activeCollectionNestedBackground : Doc.UserDoc().activeCollectionBackground);
-                        break;
-                    //if (doc._viewType !== CollectionViewType.Freeform && doc._viewType !== CollectionViewType.Time) return "rgb(62,62,62)";
-                    default: docColor = "black"; break;
-                }
-            } else {
-                switch (doc?.type) {
-                    case DocumentType.PRESELEMENT: docColor = ""; break;
-                    case DocumentType.FONTICON: docColor = "black"; break;
-                    case DocumentType.RTF: docColor = "#f1efeb"; break;
-                    case DocumentType.BUTTON:
-                    case DocumentType.LABEL: docColor = "lightgray"; break;
-                    case DocumentType.LINK:
-                    case DocumentType.COL:
-                        docColor = Doc.IsSystem(doc) ? "lightgrey" :
-                            StrCast(renderDepth > 0 ? Doc.UserDoc().activeCollectionNestedBackground :
-                                Doc.UserDoc().activeCollectionBackground);
-                        break;
-                    //if (doc._viewType !== CollectionViewType.Freeform && doc._viewType !== CollectionViewType.Time) return "lightgray";
-                    default: docColor = "white"; break;
-                }
-            }
-        }
-        if (!doc || layerProvider?.(doc) === false) {
-            return Color(docColor).fade(0.5).toString();
-        }
-        return docColor;
-    }
-
     @computed get mainDocView() {
         return <DocumentView
             Document={this.mainContainer!}
@@ -280,7 +239,6 @@ export class MainView extends React.Component {
             pinToPres={emptyFunction}
             rootSelected={returnTrue}
             onClick={undefined}
-            backgroundColor={this.defaultBackgroundColors}
             removeDocument={undefined}
             ScreenToLocalTransform={Transform.Identity}
             ContentScaling={returnOne}
@@ -352,7 +310,7 @@ export class MainView extends React.Component {
                         PanelHeight={this.getContentsHeight}
                         renderDepth={0}
                         focus={emptyFunction}
-                        backgroundColor={this.defaultBackgroundColors}
+                        styleProvider={TabDocView.styleProvider}
                         parentActive={returnTrue}
                         whenActiveChanged={emptyFunction}
                         bringToFront={emptyFunction}
@@ -387,7 +345,7 @@ export class MainView extends React.Component {
                 PanelHeight={this.getContentsHeight}
                 renderDepth={0}
                 focus={emptyFunction}
-                backgroundColor={this.defaultBackgroundColors}
+                styleProvider={TabDocView.styleProvider}
                 parentActive={returnTrue}
                 whenActiveChanged={emptyFunction}
                 bringToFront={emptyFunction}
@@ -439,7 +397,7 @@ export class MainView extends React.Component {
                 <div className="mainView-propertiesDragger" onPointerDown={this.onPropertiesPointerDown} style={{ right: this.propertiesWidth() - 1 }}>
                     <FontAwesomeIcon icon={this.propertiesWidth() < 10 ? "chevron-left" : "chevron-right"} color={this.darkScheme ? "white" : "black"} size="sm" />
                 </div>
-                {this.propertiesWidth() < 10 ? (null) : <PropertiesView backgroundColor={this.defaultBackgroundColors} width={this.propertiesWidth()} height={this.getContentsHeight()} />}
+                {this.propertiesWidth() < 10 ? (null) : <PropertiesView styleProvider={TabDocView.styleProvider} width={this.propertiesWidth()} height={this.getContentsHeight()} />}
             </div>
         </>;
     }
@@ -494,7 +452,7 @@ export class MainView extends React.Component {
                     dropAction={"alias"}
                     annotationsKey={""}
                     parentActive={returnFalse}
-                    backgroundColor={this.defaultBackgroundColors}
+                    styleProvider={TabDocView.styleProvider}
                     rootSelected={returnTrue}
                     bringToFront={emptyFunction}
                     select={emptyFunction}
@@ -570,7 +528,7 @@ export class MainView extends React.Component {
                 pinToPres={emptyFunction}
                 rootSelected={returnTrue}
                 onClick={undefined}
-                backgroundColor={this.defaultBackgroundColors}
+                styleProvider={TabDocView.styleProvider}
                 removeDocument={undefined}
                 ScreenToLocalTransform={Transform.Identity}
                 ContentScaling={returnOne}
@@ -634,7 +592,7 @@ export class MainView extends React.Component {
             <CollectionMenu />
             {LinkDescriptionPopup.descriptionPopup ? <LinkDescriptionPopup /> : null}
             {DocumentLinksButton.EditLink ? <LinkMenu docView={DocumentLinksButton.EditLink} addDocTab={DocumentLinksButton.EditLink.props.addDocTab} changeFlyout={emptyFunction} /> : (null)}
-            {LinkDocPreview.LinkInfo ? <LinkDocPreview location={LinkDocPreview.LinkInfo.Location} backgroundColor={this.defaultBackgroundColors}
+            {LinkDocPreview.LinkInfo ? <LinkDocPreview location={LinkDocPreview.LinkInfo.Location} styleProvider={TabDocView.styleProvider}
                 linkDoc={LinkDocPreview.LinkInfo.linkDoc} linkSrc={LinkDocPreview.LinkInfo.linkSrc} href={LinkDocPreview.LinkInfo.href}
                 addDocTab={LinkDocPreview.LinkInfo.addDocTab} /> : (null)}
             <GestureOverlay >
diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx
index 7d47abdce..2727ac2df 100644
--- a/src/client/views/OverlayView.tsx
+++ b/src/client/views/OverlayView.tsx
@@ -195,7 +195,7 @@ export class OverlayView extends React.Component {
                     parentActive={returnTrue}
                     whenActiveChanged={emptyFunction}
                     focus={emptyFunction}
-                    backgroundColor={returnEmptyString}
+                    styleProvider={returnEmptyString}
                     addDocTab={returnFalse}
                     pinToPres={emptyFunction}
                     docFilters={returnEmptyFilter}
diff --git a/src/client/views/Palette.tsx b/src/client/views/Palette.tsx
index 62e0fb379..536af2776 100644
--- a/src/client/views/Palette.tsx
+++ b/src/client/views/Palette.tsx
@@ -53,7 +53,7 @@ export default class Palette extends React.Component<PaletteProps> {
                             PanelHeight={() => window.screen.height}
                             renderDepth={0}
                             focus={emptyFunction}
-                            backgroundColor={returnEmptyString}
+                            styleProvider={returnEmptyString}
                             parentActive={returnTrue}
                             whenActiveChanged={emptyFunction}
                             bringToFront={emptyFunction}
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 17cfb5a5a..245e612b3 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -36,7 +36,7 @@ const _global = (window /* browser */ || global /* node */) as any;
 interface PropertiesViewProps {
     width: number;
     height: number;
-    backgroundColor: (doc: Opt<Doc>, renderDepth: number) => Opt<string>;
+    styleProvider?: (doc: Opt<Doc>, renderDepth: number, property: string, layerProvider?: (doc: Doc, assign?: boolean) => boolean) => any;
 }
 
 @observer
@@ -270,7 +270,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                     renderDepth={1}
                     rootSelected={returnFalse}
                     treeViewDoc={undefined}
-                    backgroundColor={this.props.backgroundColor}
+                    styleProvider={this.props.styleProvider}
                     fitToBox={true}
                     FreezeDimensions={true}
                     dontCenter={"y"}
diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx
index 8c58a5679..e32400385 100644
--- a/src/client/views/collections/CollectionCarouselView.tsx
+++ b/src/client/views/collections/CollectionCarouselView.tsx
@@ -65,7 +65,7 @@ export class CollectionCarouselView extends CollectionSubView(CarouselDocument)
                 </div>
                 <div className="collectionCarouselView-caption" key="caption"
                     style={{
-                        background: StrCast(this.layoutDoc._captionBackgroundColor, this.props.backgroundColor?.(this.props.Document, this.props.renderDepth, this.props.layerProvider)),
+                        background: StrCast(this.layoutDoc._captionBackgroundColor, this.props.styleProvider?.(this.props.Document, this.props.renderDepth, "color", this.props.layerProvider)),
                         color: StrCast(this.layoutDoc._captionColor, StrCast(this.layoutDoc.color)),
                         borderRadius: StrCast(this.layoutDoc._captionBorderRounding),
                     }}>
diff --git a/src/client/views/collections/CollectionLinearView.tsx b/src/client/views/collections/CollectionLinearView.tsx
index b6ab3f0e0..b427e35c3 100644
--- a/src/client/views/collections/CollectionLinearView.tsx
+++ b/src/client/views/collections/CollectionLinearView.tsx
@@ -154,7 +154,7 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
                                 PanelHeight={nested ? pair.layout[HeightSym] : this.dimension}
                                 renderDepth={this.props.renderDepth + 1}
                                 focus={emptyFunction}
-                                backgroundColor={this.props.backgroundColor}
+                                styleProvider={this.props.styleProvider}
                                 parentActive={returnTrue}
                                 whenActiveChanged={emptyFunction}
                                 bringToFront={emptyFunction}
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 41e2ad81a..4b3393e14 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -192,7 +192,7 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument,
         return <ContentFittingDocumentView
             Document={doc}
             DataDoc={dataDoc || (!Doc.AreProtosEqual(doc[DataSym], doc) && doc[DataSym])}
-            backgroundColor={this.props.backgroundColor}
+            styleProvider={this.props.styleProvider}
             LayoutTemplate={this.props.ChildLayoutTemplate}
             LayoutTemplateString={this.props.ChildLayoutString}
             LibraryPath={this.props.LibraryPath}
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 56c6978f1..85bf76e6d 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -168,7 +168,7 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll
                 rootSelected={returnTrue}
                 treeViewDoc={undefined}
                 //dontRegisterView={true}
-                backgroundColor={this.props.backgroundColor}
+                styleProvider={this.props.styleProvider}
                 PanelWidth={this.rtfWidth}
                 PanelHeight={this.rtfOutlineHeight}
                 focus={this.props.focus}
@@ -204,7 +204,7 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll
         const addDoc = (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => this.addDoc(doc, relativeTo, before);
         const moveDoc = (d: Doc | Doc[], target: Doc | undefined, addDoc: (doc: Doc | Doc[]) => boolean) => this.props.moveDocument(d, target, addDoc);
         return TreeView.GetChildElements(this.treeChildren, this, this.doc, this.props.DataDoc, this.props.fieldKey, this.props.ContainingCollectionDoc, undefined, addDoc, this.remove,
-            moveDoc, dropAction, this.props.addDocTab, this.props.pinToPres, this.props.backgroundColor, this.props.ScreenToLocalTransform,
+            moveDoc, dropAction, this.props.addDocTab, this.props.pinToPres, this.props.styleProvider, this.props.ScreenToLocalTransform,
             this.outerXf, this.active, this.props.PanelWidth, this.props.ChromeHeight, this.props.renderDepth, () => this.props.treeViewHideHeaderFields || BoolCast(this.doc.treeViewHideHeaderFields),
             BoolCast(this.doc.treeViewPreventOpen), [], this.props.onCheckedClick,
             this.onChildClick, this.props.ignoreFields, true, this.whenActiveChanged, this.props.dontRegisterView || Cast(this.props.Document.dontRegisterChildViews, "boolean", null));
@@ -216,7 +216,7 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll
     render() {
         TraceMobx();
         if (!(this.doc instanceof Doc)) return (null);
-        const background = StrCast(this.layoutDoc._backgroundColor) || StrCast(this.layoutDoc.backgroundColor) || StrCast(this.doc.backgroundColor) || this.props.backgroundColor?.(this.doc, this.props.renderDepth, this.props.layerProvider);
+        const background = this.props.styleProvider?.(this.doc, this.props.renderDepth, "color", this.props.layerProvider);
         const paddingX = `${NumCast(this.doc._xPadding, 10)}px`;
         const paddingTop = `${NumCast(this.doc._yPadding, 20)}px`;
         const pointerEvents = !this.props.active() && !SnappingManager.GetIsDragging() && !this._isChildActive ? "none" : undefined;
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 4d620bc61..e2c6bcaf6 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -398,8 +398,8 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
             ChildLayoutTemplate: this.childLayoutTemplate,
             ChildLayoutString: this.childLayoutString,
         };
-        const boxShadow = Doc.UserDoc().renderStyle === "comic" || this.props.Document.treeViewOutlineMode || Cast(this.props.Document.layers, listSpec("string"), []).includes("background") || this.collectionViewType === CollectionViewType.Linear ? undefined :
-            `${CurrentUserUtils.ActiveDashboard?.darkScheme ? "rgb(30, 32, 31) " : "#9c9396 "} ${StrCast(this.props.Document.boxShadow, "0.2vw 0.2vw 0.8vw")}`;
+        const boxShadow = Doc.UserDoc().renderStyle === "comic" || this.props.Document.treeViewOutlineMode || this.collectionViewType === CollectionViewType.Linear ? undefined :
+            this.props.styleProvider?.(this.props.Document, this.props.renderDepth, "boxShadow", this.props.layerProvider);
         return (<div className={"collectionView"} onContextMenu={this.onContextMenu}
             style={{ pointerEvents: this.props.layerProvider?.(this.props.Document) === false ? "none" : undefined, boxShadow }}>
             {this.showIsTagged()}
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 471cc639e..6d22f0420 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -6,11 +6,11 @@ import { clamp } from 'lodash';
 import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx";
 import { observer } from "mobx-react";
 import * as ReactDOM from 'react-dom';
-import { DataSym, Doc, DocListCast, Opt, DocListCastAsync } from "../../../fields/Doc";
+import { DataSym, Doc, DocListCast, Opt, DocListCastAsync, StrListCast } from "../../../fields/Doc";
 import { Id } from '../../../fields/FieldSymbols';
 import { FieldId } from "../../../fields/RefField";
 import { listSpec } from '../../../fields/Schema';
-import { Cast, NumCast, StrCast } from "../../../fields/Types";
+import { Cast, NumCast, StrCast, BoolCast } from "../../../fields/Types";
 import { TraceMobx } from '../../../fields/util';
 import { emptyFunction, emptyPath, returnFalse, returnOne, returnTrue, setupMoveUpEvents, Utils } from "../../../Utils";
 import { DocServer } from "../../DocServer";
@@ -30,6 +30,9 @@ import { CollectionViewType } from './CollectionView';
 import "./TabDocView.scss";
 import React = require("react");
 import { List } from '../../../fields/List';
+import { DocumentType } from '../../documents/DocumentTypes';
+import Color = require('color');
+import { InkTool } from '../../../fields/InkField';
 const _global = (window /* browser */ || global /* node */) as any;
 
 interface TabDocViewProps {
@@ -274,6 +277,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
     @computed get previewPanelCenteringOffset() { return this.nativeWidth() ? (this._panelWidth - this.nativeWidth() * this.ContentScaling()) / 2 : 0; }
     @computed get widthpercent() { return this.nativeWidth() ? `${(this.nativeWidth() * this.ContentScaling()) / this._panelWidth * 100}% ` : undefined; }
     @computed get layoutDoc() { return this._document && Doc.Layout(this._document); }
+    @computed static get darkScheme() { return BoolCast(CurrentUserUtils.ActiveDashboard?.darkScheme); }
 
     // adds a tab to the layout based on the locaiton parameter which can be:
     //  close[:{left,right,top,bottom}]  - e.g., "close" will close the tab, "close:left" will close the left tab, 
@@ -297,7 +301,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
         }
     }
 
-    @computed get tabColor() { return StrCast(this._document?._backgroundColor, StrCast(this._document?.backgroundColor, CollectionDockingView.Instance.props.backgroundColor?.(this._document, 0))); }
+    @computed get tabColor() { return StrCast(this._document?._backgroundColor, StrCast(this._document?.backgroundColor, TabDocView.styleProvider(this._document, 0, "color"))); }
     @computed get renderBounds() {
         const bounds = this._document ? Cast(this._document._renderContentBounds, listSpec("number"), [0, 0, this.returnMiniSize(), this.returnMiniSize()]) : [0, 0, 0, 0];
         const xbounds = bounds[2] - bounds[0];
@@ -355,7 +359,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                     renderDepth={0}
                     whenActiveChanged={emptyFunction}
                     focus={emptyFunction}
-                    backgroundColor={CollectionDockingView.Instance.props.backgroundColor}
+                    styleProvider={TabDocView.styleProvider}
                     addDocTab={this.addDocTab}
                     pinToPres={TabDocView.PinDoc}
                     docFilters={CollectionDockingView.Instance.docFilters}
@@ -370,7 +374,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
 
             <Tooltip title={<div className="dash-tooltip">{"toggle minimap"}</div>}>
                 <div className="miniMap-hidden" onPointerDown={e => e.stopPropagation()} onClick={action(e => { e.stopPropagation(); this._document!.hideMinimap = !this._document!.hideMinimap; })}
-                    style={{ background: CollectionDockingView.Instance.props.backgroundColor?.(this._document, 0) }} >
+                    style={{ background: TabDocView.styleProvider(this._document, 0, "color") }} >
                     <FontAwesomeIcon icon={"globe-asia"} size="lg" />
                 </div>
             </Tooltip>
@@ -385,6 +389,11 @@ export class TabDocView extends React.Component<TabDocViewProps> {
     setView = action((view: DocumentView) => this._view = view);
     active = () => this._isActive;
 
+    //
+    // a preliminary semantic-"layering/grouping" mechanism for determining interactive properties of documents
+    //  currently, the provider tests whether the docuemnt's layer field matches the activeLayer field of the tab.
+    //     if it matches, then the document gets pointer events, otherwise it does not.
+    //
     layerProvider = (doc: Doc, assign?: boolean) => {
         if (doc.z) return true;
         if (assign) {
@@ -404,6 +413,80 @@ export class TabDocView extends React.Component<TabDocViewProps> {
             return false;
         }
     }
+
+    @undoBatch
+    @action
+    static toggleBackground = (doc: Doc) => {
+        const layers = StrListCast(doc.layers);
+        if (!layers.includes("background")) {
+            if (!layers.length) doc.layers = new List<string>(["background"]);
+            else layers.push("background");
+        }
+        else layers.splice(layers.indexOf("background"), 1);
+        doc._overflow = !layers.includes("background") ? "visible" : undefined;
+        if (!layers.includes("background")) {
+            //this.props.bringToFront(doc, true);
+            // const wid = this.Document[WidthSym]();    // change the nativewidth and height if the background is to be a collection that aggregates stuff that is added to it.
+            // const hgt = this.Document[HeightSym]();
+            // Doc.SetNativeWidth(this.props.Document[DataSym], wid);
+            // Doc.SetNativeHeight(this.props.Document[DataSym], hgt);
+        }
+    }
+    //
+    // a preliminary implementation of a dash style sheet for setting rendering properties of documents nested within a Tab
+    // 
+    public static styleProvider = (doc: Opt<Doc>, renderDepth: number, property: string, layerProvider?: (doc: Doc, assign?: boolean) => boolean): any => {
+        if (property === "color") {
+            if (Doc.UserDoc().renderStyle === "comic") return undefined;
+            let docColor = StrCast(doc?._backgroundColor, StrCast(doc?.backgroundColor));
+            if (!docColor) {
+                switch (doc?.type) {
+                    case DocumentType.PRESELEMENT: docColor = TabDocView.darkScheme ? "dimgrey" : ""; break;
+                    case DocumentType.PRES: docColor = TabDocView.darkScheme ? "#3e3e3e" : "black"; break;
+                    case DocumentType.FONTICON: docColor = "black"; break;
+                    case DocumentType.RTF: docColor = TabDocView.darkScheme ? "#2d2d2d" : "#f1efeb";
+                    case DocumentType.LABEL:
+                    case DocumentType.BUTTON: docColor = TabDocView.darkScheme ? "#2d2d2d" : "lightgray"; break;
+                    case DocumentType.LINK:
+                    case DocumentType.COL:
+                        docColor = Doc.IsSystem(doc) ? (TabDocView.darkScheme ? "rgb(62,62,62)" : "lightgrey") :
+                            StrCast(renderDepth > 0 ? Doc.UserDoc().activeCollectionNestedBackground : Doc.UserDoc().activeCollectionBackground);
+                        break;
+                    //if (doc._viewType !== CollectionViewType.Freeform && doc._viewType !== CollectionViewType.Time) return "rgb(62,62,62)";
+                    default: docColor = TabDocView.darkScheme ? "black" : "white"; break;
+                }
+            }
+            if (docColor && (!doc || layerProvider?.(doc) === false)) docColor = Color(docColor).fade(0.5).toString();
+            return docColor;
+        }
+        if (property.startsWith("pointerEvents")) {
+            const layer = doc && layerProvider?.(doc);
+            if (layer === false && !property.includes(":selected") && !SnappingManager.GetIsDragging()) return "none";
+            if (doc?.type === DocumentType.INK && Doc.GetSelectedTool() !== InkTool.None) return "none";
+            if (layer === true) return "all";
+            return undefined;
+        }
+        if (property.startsWith("decorations")) {
+            const isBackground = StrListCast(doc?.layers).includes("background");
+            return doc && (isBackground || property.includes(":selected")) && renderDepth > 0 &&
+                ((doc.type === DocumentType.COL && doc._viewType !== CollectionViewType.Pile) || [DocumentType.RTF, DocumentType.IMG, DocumentType.INK].includes(doc.type as DocumentType)) ?
+                <div className="documentView-lock" onClick={() => TabDocView.toggleBackground(doc)}>
+                    <FontAwesomeIcon icon={isBackground ? "unlock" : "lock"} style={{ color: isBackground ? "red" : undefined }} size="lg" />
+                </div>
+                : (null);
+        }
+        if (property === "hidden") {
+            if (doc && (doc.hidden /* || layerProvider?.(doc) === false*/)) return true;
+            return false;
+        }
+        if (property === "boxShadow") {
+            switch (doc?.type) {
+                case DocumentType.COL: return StrListCast(doc.layers).includes("background") ? undefined :
+                    `${TabDocView.darkScheme ? "rgb(30, 32, 31) " : "#9c9396 "} ${StrCast(doc.boxShadow, "0.2vw 0.2vw 0.8vw")}`;
+            }
+            return undefined;
+        }
+    }
     @computed get docView() {
         TraceMobx();
         return !this._activated || !this._document || this._document._viewType === CollectionViewType.Docking ? (null) :
@@ -427,7 +510,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                 parentActive={this.active}
                 whenActiveChanged={emptyFunction}
                 focus={this.focusFunc}
-                backgroundColor={CollectionDockingView.Instance.props.backgroundColor}
+                styleProvider={TabDocView.styleProvider}
                 addDocTab={this.addDocTab}
                 pinToPres={TabDocView.PinDoc}
                 docFilters={CollectionDockingView.Instance.docFilters}
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index ce13c1d38..cb521ea75 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -49,7 +49,7 @@ export interface TreeViewProps {
     outdentDocument?: () => void;
     ScreenToLocalTransform: () => Transform;
     dontRegisterView?: boolean;
-    backgroundColor?: (doc: Opt<Doc>, renderDepth: number) => string | undefined;
+    backgroundColor?: (doc: Opt<Doc>, renderDepth: number, property: string, layerProvider?: (doc: Doc, assign?: boolean) => boolean) => string | undefined;
     outerXf: () => { translateX: number, translateY: number };
     treeView: CollectionTreeView;
     parentKey: string;
@@ -579,7 +579,7 @@ export class TreeView extends React.Component<TreeViewProps> {
             renderDepth={this.props.renderDepth + 1}
             rootSelected={returnTrue}
             treeViewDoc={undefined}
-            backgroundColor={this.props.backgroundColor}
+            styleProvider={this.props.backgroundColor}
             docFilters={returnEmptyFilter}
             docRangeFilters={returnEmptyFilter}
             searchFilterDocs={returnEmptyDoclist}
@@ -661,7 +661,7 @@ export class TreeView extends React.Component<TreeViewProps> {
         dropAction: dropActionType,
         addDocTab: (doc: Doc, where: string) => boolean,
         pinToPres: (document: Doc) => void,
-        backgroundColor: undefined | ((document: Opt<Doc>, renderDepth: number) => string | undefined),
+        backgroundColor: undefined | ((document: Opt<Doc>, renderDepth: number, property: string, layerProvider?: (doc: Doc, assign?: boolean) => boolean) => string | undefined),
         screenToLocalXf: () => Transform,
         outerXf: () => { translateX: number, translateY: number },
         active: (outsideReaction?: boolean) => boolean,
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index f36518439..84f82beda 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -393,8 +393,9 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
         }
     }
 
-    getClusterColor = (doc: Opt<Doc>, renderDepth: number, layerProvider?: (doc: Doc, assign?: boolean) => boolean) => {
-        let clusterColor = this.props.backgroundColor?.(doc, this.props.renderDepth + 1, layerProvider);
+    getClusterColor = (doc: Opt<Doc>, renderDepth: number, property: string, layerProvider?: (doc: Doc, assign?: boolean) => boolean) => {
+        let clusterColor = this.props.styleProvider?.(doc, this.props.renderDepth + 1, property, layerProvider);
+        if (property !== "color") return clusterColor;
         const cluster = NumCast(doc?.cluster);
         if (this.Document._useClusters) {
             if (this._clusterSets.length <= cluster) {
@@ -1016,7 +1017,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
             docRangeFilters: this.docRangeFilters,
             searchFilterDocs: this.searchFilterDocs,
             focus: this.focusDocument,
-            backgroundColor: this.getClusterColor,
+            styleProvider: this.getClusterColor,
             backgroundHalo: this.backgroundHalo(childLayout),
             bringToFront: this.bringToFront,
             addDocTab: this.addDocTab,
diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.tsx b/src/client/views/collections/collectionGrid/CollectionGridView.tsx
index 8e86b6d0d..f3e385746 100644
--- a/src/client/views/collections/collectionGrid/CollectionGridView.tsx
+++ b/src/client/views/collections/collectionGrid/CollectionGridView.tsx
@@ -165,7 +165,7 @@ export class CollectionGridView extends CollectionSubView(GridSchema) {
             {...OmitKeys(this.props, ["NativeWidth", "NativeHeight"]).omit}
             Document={layout}
             DataDoc={layout.resolvedDataDoc as Doc}
-            backgroundColor={this.props.backgroundColor}
+            styleProvider={this.props.styleProvider}
             ContainingCollectionDoc={this.props.Document}
             PanelWidth={width}
             PanelHeight={height}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index 6e16137b5..2e7cdf6d0 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -216,7 +216,7 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
         return <ContentFittingDocumentView
             Document={layout}
             DataDoc={layout.resolvedDataDoc as Doc}
-            backgroundColor={this.props.backgroundColor}
+            styleProvider={this.props.styleProvider}
             LayoutTemplate={this.props.ChildLayoutTemplate}
             LayoutTemplateString={this.props.ChildLayoutString}
             LibraryPath={this.props.LibraryPath}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index c5e1816d9..4206a5171 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -216,7 +216,7 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument)
         return <ContentFittingDocumentView
             Document={layout}
             DataDoc={layout.resolvedDataDoc as Doc}
-            backgroundColor={this.props.backgroundColor}
+            styleProvider={this.props.styleProvider}
             LayoutTemplate={this.props.ChildLayoutTemplate}
             LayoutTemplateString={this.props.ChildLayoutString}
             LibraryPath={this.props.LibraryPath}
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index cba65f663..4f6c5cebe 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -623,7 +623,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
                                             ContainingCollectionDoc={this.props.Document}
                                             parentActive={returnTrue}
                                             bringToFront={emptyFunction}
-                                            backgroundColor={returnTransparent}
+                                            styleProvider={returnTransparent}
                                             ContentScaling={returnOne}
                                             forcedBackgroundColor={returnTransparent}
                                             pointerEvents={"none"}
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index e6cb160dd..caacd1bd4 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -208,7 +208,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
             dragDivName={"collectionFreeFormDocumentView-container"}
             ContentScaling={this.contentScaling}
             ScreenToLocalTransform={this.getTransform}
-            backgroundColor={this.props.backgroundColor}
+            styleProvider={this.props.styleProvider}
             opacity={this.opacity}
             layerProvider={this.props.layerProvider}
             NativeHeight={this.NativeHeight}
@@ -251,22 +251,18 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
     NativeHeight = () => this.nativeHeight;
     @computed get pointerEvents() {
         if (this.props.pointerEvents === "none") return "none";
-        const layer = this.props.layerProvider?.(this.Document);
-        if (layer === false && !this._contentView?.docView?.isSelected() && !SnappingManager.GetIsDragging()) return "none";
-        if (this.Document.type === DocumentType.INK && Doc.GetSelectedTool() !== InkTool.None) return "none";
-        if (layer === true) return "all";
-        return this.props.pointerEvents;
+        return this.props.styleProvider?.(this.Document, this.props.renderDepth, !this._contentView?.docView?.isSelected() ? "pointerEvents:selected" : "pointerEvents", this.props.layerProvider);
     }
     render() {
         TraceMobx();
-        const backgroundColor = StrCast(this.layoutDoc._backgroundColor) || StrCast(this.layoutDoc.backgroundColor) || StrCast(this.Document.backgroundColor) || this.props.backgroundColor?.(this.Document, this.props.renderDepth, this.props.layerProvider);
+        const backgroundColor = this.props.styleProvider?.(this.Document, this.props.renderDepth, "color", this.props.layerProvider);
         const borderRounding = StrCast(Doc.Layout(this.layoutDoc).borderRounding) || StrCast(this.layoutDoc.borderRounding) || StrCast(this.Document.borderRounding) || undefined;
         return <div className="collectionFreeFormDocumentView-container"
             style={{
                 boxShadow:
                     this.Opacity === 0 ? undefined :  // if it's not visible, then no shadow
                         this.layoutDoc.z ? `#9c9396  ${StrCast(this.layoutDoc.boxShadow, "10px 10px 0.9vw")}` :  // if it's a floating doc, give it a big shadow
-                            this.props.backgroundHalo?.() && this.props.Document.type !== DocumentType.INK ? (`${this.props.backgroundColor?.(this.props.Document, this.props.renderDepth, this.props.layerProvider)} ${StrCast(this.layoutDoc.boxShadow, `0vw 0vw ${(Cast(this.layoutDoc.layers, listSpec("string"), []).includes("background") ? 100 : 50) / this.props.ContentScaling()}px`)}`) :  // if it's just in a cluster, make the shadown roughly match the cluster border extent
+                            this.props.backgroundHalo?.() && this.props.Document.type !== DocumentType.INK ? (`${this.props.styleProvider?.(this.props.Document, this.props.renderDepth, "color", this.props.layerProvider)} ${StrCast(this.layoutDoc.boxShadow, `0vw 0vw ${(Cast(this.layoutDoc.layers, listSpec("string"), []).includes("background") ? 100 : 50) / this.props.ContentScaling()}px`)}`) :  // if it's just in a cluster, make the shadown roughly match the cluster border extent
                                 Cast(this.layoutDoc.layers, listSpec("string"), []).includes('background') ? undefined :  // if it's a background & has a cluster color, make the shadow spread really big
                                     StrCast(this.layoutDoc.boxShadow, ""),
                 borderRadius: borderRounding,
diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx
index 5c2a7843f..a54479f55 100644
--- a/src/client/views/nodes/ContentFittingDocumentView.tsx
+++ b/src/client/views/nodes/ContentFittingDocumentView.tsx
@@ -79,7 +79,7 @@ export class ContentFittingDocumentView extends React.Component<DocumentViewProp
                         layoutKey={this.props.layoutKey}
                         dropAction={this.props.dropAction}
                         onClick={this.props.onClick}
-                        backgroundColor={this.props.backgroundColor}
+                        styleProvider={this.props.styleProvider}
                         addDocument={this.props.addDocument}
                         removeDocument={this.props.removeDocument}
                         moveDocument={this.props.moveDocument}
diff --git a/src/client/views/nodes/DocHolderBox.tsx b/src/client/views/nodes/DocHolderBox.tsx
index b5e0df659..a20423fdc 100644
--- a/src/client/views/nodes/DocHolderBox.tsx
+++ b/src/client/views/nodes/DocHolderBox.tsx
@@ -125,7 +125,7 @@ export class DocHolderBox extends ViewBoxAnnotatableComponent<FieldViewProps, Do
                     ContainingCollectionView={this as any} // bcz: hack!  need to pass a prop that can be used to select the container (ie, 'this') when the up selector in document decorations is clicked.  currently, the up selector allows only a containing collection to be selected
                     ContainingCollectionDoc={undefined}
                     fitToBox={true}
-                    backgroundColor={this.props.backgroundColor}
+                    styleProvider={this.props.styleProvider}
                     LayoutTemplateString={layoutTemplate}
                     LayoutTemplate={this.layoutTemplateDoc}
                     rootSelected={this.props.isSelected}
@@ -154,7 +154,7 @@ export class DocHolderBox extends ViewBoxAnnotatableComponent<FieldViewProps, Do
                     ContainingCollectionView={this as any} // bcz: hack!  need to pass a prop that can be used to select the container (ie, 'this') when the up selector in document decorations is clicked.  currently, the up selector allows only a containing collection to be selected
                     ContainingCollectionDoc={undefined}
                     fitToBox={true}
-                    backgroundColor={this.props.backgroundColor}
+                    styleProvider={this.props.styleProvider}
                     ignoreAutoHeight={true}
                     LayoutTemplateString={layoutTemplate}
                     LayoutTemplate={this.layoutTemplateDoc}
@@ -184,7 +184,7 @@ export class DocHolderBox extends ViewBoxAnnotatableComponent<FieldViewProps, Do
             onContextMenu={this.specificContextMenu}
             onPointerDown={this.onPointerDown} onClick={this.onClick}
             style={{
-                background: this.props.backgroundColor?.(containedDoc, this.props.renderDepth, this.props.layerProvider),
+                background: this.props.styleProvider?.(containedDoc, this.props.renderDepth, "color", this.props.layerProvider),
                 border: `#00000021 solid ${this.xPad}px`,
                 borderTop: `#0000005e solid ${this.yPad}px`,
                 borderBottom: `#0000005e solid ${this.yPad}px`,
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 067732a80..9e24d2284 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1,7 +1,7 @@
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { action, computed, observable, runInAction } from "mobx";
 import { observer } from "mobx-react";
-import { AclAdmin, AclEdit, AclPrivate, DataSym, Doc, DocListCast, Field, HeightSym, Opt, WidthSym } from "../../../fields/Doc";
+import { AclAdmin, AclEdit, AclPrivate, DataSym, Doc, DocListCast, Field, HeightSym, Opt, WidthSym, StrListCast } from "../../../fields/Doc";
 import { Document } from '../../../fields/documentSchemas';
 import { Id } from '../../../fields/FieldSymbols';
 import { InkTool } from '../../../fields/InkField';
@@ -93,7 +93,7 @@ export interface DocumentViewProps {
     addDocTab: (doc: Doc, where: string, libraryPath?: Doc[]) => boolean;
     pinToPres: (document: Doc) => void;
     backgroundHalo?: () => boolean;
-    backgroundColor?: (doc: Opt<Doc>, renderDepth: number, layerProvider?: (doc: Doc, assign?: boolean) => boolean) => string | undefined;
+    styleProvider?: (doc: Opt<Doc>, renderDepth: number, property: string, layerProvider?: (doc: Doc, assign?: boolean) => boolean) => any;
     forcedBackgroundColor?: (doc: Doc) => string | undefined;
     opacity?: () => number | undefined;
     ChromeHeight?: () => number;
@@ -745,24 +745,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         this.Document.isLinkButton = true;
     }
 
-    @undoBatch
-    @action
-    toggleBackground = () => {
-        const layers = Cast(this.Document.layers, listSpec("string"), []);
-        if (!layers.includes("background")) {
-            if (!layers.length) this.Document.layers = new List<string>(["background"]);
-            else layers.push("background");
-        }
-        else layers.splice(layers.indexOf("background"), 1);
-        this.Document._overflow = !layers.includes("background") ? "visible" : undefined;
-        if (!layers.includes("background")) {
-            this.props.bringToFront(this.props.Document, true);
-            // const wid = this.Document[WidthSym]();    // change the nativewidth and height if the background is to be a collection that aggregates stuff that is added to it.
-            // const hgt = this.Document[HeightSym]();
-            // Doc.SetNativeWidth(this.props.Document[DataSym], wid);
-            // Doc.SetNativeHeight(this.props.Document[DataSym], hgt);
-        }
-    }
 
     @action
     onCopy = () => {
@@ -966,7 +948,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 bringToFront={this.props.bringToFront}
                 addDocTab={this.props.addDocTab}
                 pinToPres={this.props.pinToPres}
-                backgroundColor={this.props.backgroundColor}
+                styleProvider={this.props.styleProvider}
                 ContentScaling={this.childScaling}
                 ChromeHeight={this.chromeHeight}
                 isSelected={this.isSelected}
@@ -1083,11 +1065,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     }
     @computed get pointerEvents() {
         if (this.props.pointerEvents === "none") return "none";
-        const layer = this.props.layerProvider?.(this.Document);
-        if (layer === false && !this.isSelected() && !SnappingManager.GetIsDragging()) return "none";
-        if (this.Document.type === DocumentType.INK && Doc.GetSelectedTool() !== InkTool.None) return "none";
-        if (layer === true) return "all";
-        return undefined;
+        return this.props.styleProvider?.(this.Document, this.props.renderDepth, this.isSelected() ? "pointerEvents:selected" : "pointerEvents", this.props.layerProvider);
     }
     @undoBatch
     @action
@@ -1107,23 +1085,13 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         }), 400);
     });
 
-    renderLock() {
-        const isBackground = Cast(this.Document.layers, listSpec("string"), []).includes("background");
-        return (isBackground || this.isSelected(false)) &&
-            ((this.Document.type === DocumentType.COL && this.Document._viewType !== CollectionViewType.Pile) || this.Document.type === DocumentType.RTF || this.Document.type === DocumentType.IMG || this.Document.type === DocumentType.INK) &&
-            this.props.renderDepth > 0 && !this.props.treeViewDoc ?
-            <div className="documentView-lock" onClick={this.toggleBackground}>
-                <FontAwesomeIcon icon={isBackground ? "unlock" : "lock"} style={{ color: isBackground ? "red" : undefined }} size="lg" />
-            </div>
-            : (null);
-    }
 
     render() {
         TraceMobx();
         if (!(this.props.Document instanceof Doc)) return (null);
         if (GetEffectiveAcl(this.props.Document[DataSym]) === AclPrivate) return (null);
-        if (this.props.Document.hidden) return (null);
-        const backgroundColor = Doc.UserDoc().renderStyle === "comic" ? undefined : this.props.forcedBackgroundColor?.(this.Document) || this.props.backgroundColor?.(this.layoutDoc, this.props.renderDepth, this.props.layerProvider);
+        if (this.props.styleProvider?.(this.layoutDoc, this.props.renderDepth, "hidden", this.props.layerProvider)) return null;
+        const backgroundColor = this.props.forcedBackgroundColor?.(this.Document) || this.props.styleProvider?.(this.layoutDoc, this.props.renderDepth, "color", this.props.layerProvider);
         const opacity = Cast(this.layoutDoc._opacity, "number", Cast(this.layoutDoc.opacity, "number", Cast(this.Document.opacity, "number", null)));
         const finalOpacity = this.props.opacity ? this.props.opacity() : opacity;
         const finalColor = this.layoutDoc.type === DocumentType.FONTICON || this.layoutDoc._viewType === CollectionViewType.Linear ? undefined : backgroundColor;
@@ -1159,7 +1127,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 transformOrigin: this._animateScalingTo ? "center center" : undefined,
                 transform: this._animateScalingTo ? `scale(${this._animateScalingTo})` : undefined,
                 transition: !this._animateScalingTo ? StrCast(this.Document.dataTransition) : `transform 0.5s ease-${this._animateScalingTo < 1 ? "in" : "out"}`,
-                pointerEvents: this.pointerEvents,
+                pointerEvents: this.pointerEvents as any,
                 color: StrCast(this.layoutDoc.color, "inherit"),
                 outline: highlighting && !borderRounding ? `${highlightColors[fullDegree]} ${highlightStyles[fullDegree]} ${localScale}px` : "solid 0px",
                 border: highlighting && borderRounding && highlightStyles[fullDegree] === "dashed" ? `${highlightStyles[fullDegree]} ${highlightColors[fullDegree]} ${localScale}px` : undefined,
@@ -1178,7 +1146,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 <div className="documentView-contentBlocker" />
             </> :
                 this.innards}
-            {this.renderLock()}
+            {!this.props.treeViewDoc && this.props.styleProvider?.(this.rootDoc, this.props.renderDepth, this.isSelected() ? "decorations:selected" : "decorations", this.props.layerProvider) || (null)}
         </div>;
     }
 }
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index b8f2d5d6f..9df3e6b81 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -43,7 +43,7 @@ export interface FieldViewProps {
     pinToPres: (document: Doc) => void;
     removeDocument?: (document: Doc | Doc[]) => boolean;
     moveDocument?: (document: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => boolean;
-    backgroundColor?: (document: Opt<Doc>, renderDepth: number, layerProvider?: (doc: Doc, assign?: boolean) => boolean) => string | undefined;
+    styleProvider?: (document: Opt<Doc>, renderDepth: number, property: string, layerProvider?: (doc: Doc, assign?: boolean) => boolean) => any;
     ScreenToLocalTransform: () => Transform;
     bringToFront: (doc: Doc, sendToBack?: boolean) => void;
     parentActive: (outsideReaction: boolean) => boolean;
diff --git a/src/client/views/nodes/FilterBox.tsx b/src/client/views/nodes/FilterBox.tsx
index 24cd6f21f..4db421e7a 100644
--- a/src/client/views/nodes/FilterBox.tsx
+++ b/src/client/views/nodes/FilterBox.tsx
@@ -214,7 +214,7 @@ export class FilterBox extends ViewBoxBaseComponent<FieldViewProps, FilterBoxDoc
                     ignoreFields={this.ignoreFields}
                     annotationsKey={""}
                     dontRegisterView={true}
-                    backgroundColor={this.filterBackground}
+                    styleProvider={this.filterBackground}
                     moveDocument={returnFalse}
                     removeDocument={returnFalse}
                     addDocument={returnFalse} />
diff --git a/src/client/views/nodes/FontIconBox.tsx b/src/client/views/nodes/FontIconBox.tsx
index 8eb107274..d4b6f1a27 100644
--- a/src/client/views/nodes/FontIconBox.tsx
+++ b/src/client/views/nodes/FontIconBox.tsx
@@ -61,7 +61,7 @@ export class FontIconBox extends DocComponent<FieldViewProps, FontIconDocument>(
     render() {
         const label = StrCast(this.rootDoc.label, StrCast(this.rootDoc.title));
         const color = StrCast(this.layoutDoc.color, this._foregroundColor);
-        const backgroundColor = StrCast(this.layoutDoc._backgroundColor, StrCast(this.rootDoc.backgroundColor, this.props.backgroundColor?.(this.rootDoc, this.props.renderDepth, this.props.layerProvider)));
+        const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props.renderDepth, "color", this.props.layerProvider);
         const shape = StrCast(this.layoutDoc.iconShape, label ? "round" : "circle");
         const icon = StrCast(this.dataDoc.icon, "user") as any;
         const presSize = shape === 'round' ? 25 : 30;
diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx
index f80eb8f79..edad14e96 100644
--- a/src/client/views/nodes/LinkBox.tsx
+++ b/src/client/views/nodes/LinkBox.tsx
@@ -17,7 +17,7 @@ export class LinkBox extends ViewBoxBaseComponent<FieldViewProps, LinkDocument>(
     public static LayoutString(fieldKey: string) { return FieldView.LayoutString(LinkBox, fieldKey); }
     render() {
         return <div className={`linkBox-container${this.active() ? "-interactive" : ""}`}
-            style={{ background: this.props.backgroundColor?.(this.props.Document, this.props.renderDepth, this.props.layerProvider) }} >
+            style={{ background: this.props.styleProvider?.(this.props.Document, this.props.renderDepth, "color", this.props.layerProvider) }} >
 
             <CollectionTreeView {...this.props}
                 ChromeHeight={returnZero}
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx
index d47942bd9..dfdca7ebb 100644
--- a/src/client/views/nodes/LinkDocPreview.tsx
+++ b/src/client/views/nodes/LinkDocPreview.tsx
@@ -16,7 +16,7 @@ interface Props {
     linkDoc?: Doc;
     linkSrc?: Doc;
     href?: string;
-    backgroundColor: (doc: Opt<Doc>, renderDepth: number) => string;
+    styleProvider?: (doc: Opt<Doc>, renderDepth: number, property: string, layerProvider?: (doc: Doc, assign?: boolean) => boolean) => any;
     addDocTab: (document: Doc, where: string) => boolean;
     location: number[];
 }
@@ -112,7 +112,7 @@ export class LinkDocPreview extends React.Component<Props> {
                 whenActiveChanged={returnFalse}
                 bringToFront={returnFalse}
                 ContentScaling={returnOne}
-                backgroundColor={this.props.backgroundColor} />;
+                styleProvider={this.props.styleProvider} />;
     }
 
     render() {
diff --git a/src/client/views/nodes/formattedText/DashDocView.tsx b/src/client/views/nodes/formattedText/DashDocView.tsx
index 7cd92b8b9..67bfd435b 100644
--- a/src/client/views/nodes/formattedText/DashDocView.tsx
+++ b/src/client/views/nodes/formattedText/DashDocView.tsx
@@ -240,7 +240,7 @@ export class DashDocView extends React.Component<IDashDocView> {
                             PanelWidth={finalLayout[WidthSym]}
                             PanelHeight={finalLayout[HeightSym]}
                             focus={this.outerFocus}
-                            backgroundColor={returnEmptyString}
+                            styleProvider={returnEmptyString}
                             parentActive={returnFalse}
                             whenActiveChanged={returnFalse}
                             bringToFront={emptyFunction}
diff --git a/src/client/views/nodes/formattedText/RichTextSchema.tsx b/src/client/views/nodes/formattedText/RichTextSchema.tsx
index 40c1d1cac..b5d984aac 100644
--- a/src/client/views/nodes/formattedText/RichTextSchema.tsx
+++ b/src/client/views/nodes/formattedText/RichTextSchema.tsx
@@ -148,7 +148,7 @@ export class DashDocView {
                     PanelWidth={finalLayout[WidthSym]}
                     PanelHeight={finalLayout[HeightSym]}
                     focus={this.outerFocus}
-                    backgroundColor={returnEmptyString}
+                    styleProvider={returnEmptyString}
                     parentActive={returnFalse}
                     whenActiveChanged={returnFalse}
                     bringToFront={emptyFunction}
diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx
index 574bda970..8d4bd4b8b 100644
--- a/src/client/views/presentationview/PresElementBox.tsx
+++ b/src/client/views/presentationview/PresElementBox.tsx
@@ -88,7 +88,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
                     DataDoc={this.targetDoc[DataSym] !== this.targetDoc && this.targetDoc[DataSym]}
                     LibraryPath={emptyPath}
                     fitToBox={true}
-                    backgroundColor={this.props.backgroundColor}
+                    styleProvider={this.props.styleProvider}
                     rootSelected={returnTrue}
                     addDocument={returnFalse}
                     removeDocument={returnFalse}
@@ -312,7 +312,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
                     <div className="presItem-number">
                         {`${this.indexInPres + 1}.`}
                     </div>}
-                {miniView ? (null) : <div ref={miniView ? null : this._dragRef} className={`presItem-slide ${isSelected ? "active" : ""}`} style={{ backgroundColor: this.props.backgroundColor?.(this.layoutDoc, this.props.renderDepth, this.props.layerProvider) }}>
+                {miniView ? (null) : <div ref={miniView ? null : this._dragRef} className={`presItem-slide ${isSelected ? "active" : ""}`} style={{ backgroundColor: this.props.styleProvider?.(this.layoutDoc, this.props.renderDepth, "color", this.props.layerProvider) }}>
                     <div className="presItem-name" style={{ maxWidth: showMore ? (toolbarWidth - 185) : toolbarWidth - 95, cursor: isSelected ? 'text' : 'grab' }}>
                         <EditableView
                             ref={this._titleRef}
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 4c3c45d92..7b01d60e5 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -76,6 +76,7 @@ export function DocListCastAsync(field: FieldResult, defaultValue?: Doc[]) {
 
 export async function DocCastAsync(field: FieldResult): Promise<Opt<Doc>> { return Cast(field, Doc); }
 
+export function StrListCast(field: FieldResult) { return Cast(field, listSpec("string"), []) as string[]; }
 export function DocListCast(field: FieldResult) { return Cast(field, listSpec(Doc), []).filter(d => d instanceof Doc) as Doc[]; }
 export function DocListCastOrNull(field: FieldResult) { return Cast(field, listSpec(Doc), null)?.filter(d => d instanceof Doc) as Doc[] | undefined; }
 
diff --git a/src/mobile/AudioUpload.tsx b/src/mobile/AudioUpload.tsx
index ebc8bc8a7..604c9a5ab 100644
--- a/src/mobile/AudioUpload.tsx
+++ b/src/mobile/AudioUpload.tsx
@@ -97,7 +97,7 @@ export class AudioUpload extends React.Component {
                         PanelHeight={() => 400}
                         renderDepth={0}
                         focus={emptyFunction}
-                        backgroundColor={() => "rgba(0,0,0,0)"}
+                        styleProvider={() => "rgba(0,0,0,0)"}
                         parentActive={returnTrue}
                         whenActiveChanged={emptyFunction}
                         bringToFront={emptyFunction}
diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx
index a42d85b56..ae88a2eaf 100644
--- a/src/mobile/MobileInterface.tsx
+++ b/src/mobile/MobileInterface.tsx
@@ -215,7 +215,7 @@ export class MobileInterface extends React.Component {
                     PanelHeight={this.returnHeight}
                     renderDepth={0}
                     focus={emptyFunction}
-                    backgroundColor={this.whitebackground}
+                    styleProvider={this.whitebackground}
                     parentActive={returnTrue}
                     whenActiveChanged={emptyFunction}
                     bringToFront={emptyFunction}
-- 
cgit v1.2.3-70-g09d2


From e58f51695864c4d3069d8aae25582b9a9a518799 Mon Sep 17 00:00:00 2001
From: geireann <60007097+geireann@users.noreply.github.com>
Date: Sat, 28 Nov 2020 05:02:01 +0800
Subject: audio in pres updates + pre-loader

---
 deploy/index.html                                  | 75 +++++++++++++++++-----
 src/client/util/CurrentUserUtils.ts                |  2 +-
 src/client/views/PropertiesView.tsx                |  6 +-
 src/client/views/collections/TabDocView.tsx        |  4 +-
 src/client/views/nodes/AudioBox.tsx                | 31 +++++++--
 src/client/views/nodes/PresBox.tsx                 | 26 ++++----
 .../views/presentationview/PresElementBox.tsx      |  2 +
 7 files changed, 106 insertions(+), 40 deletions(-)

(limited to 'src/client/views/PropertiesView.tsx')

diff --git a/deploy/index.html b/deploy/index.html
index 7b68af2ef..af67ac301 100644
--- a/deploy/index.html
+++ b/deploy/index.html
@@ -4,29 +4,74 @@
     <title>Dash Web</title>
     <link href="https://fonts.googleapis.com/css?family=Fjalla+One|Hind+Siliguri:300" rel="stylesheet">
     <link href='https://fonts.googleapis.com/css?family=Roboto:300,400,500' rel='stylesheet'>
-    <link rel="stylesheet" href="loader.css">
-    <link rel="stylesheet" href="loader.css?rnd=23">
     <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
         integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
     <script src="https://cdnjs.cloudflare.com/ajax/libs/typescript/3.3.1/typescript.min.js"></script>
+    <style>
+        .dash-loader {
+            display: flex;
+            align-content: center;
+            justify-content: center;
+            background-color: #AEDDF8;
+            z-index: 10;
+            width: 100%;
+            height: 100%;
+        }
+
+        .dash-loader-container {
+            width: 20vw;
+            height: 20vw;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            border-radius: 100%;
+            background-color: #5B9FDD;
+            align-self: center;
+        }
+
+        .dash-d-path {
+            stroke-dasharray: 1000;
+            stroke-dashoffset: 1000;
+            animation: dash-d-path 3s linear infinite;
+        }
+
+        @keyframes dash-d-path {
+            0% {
+                stroke-dashoffset: 1000;
+                /* stroke-width: 0px; */
+            }
+
+            20% {
+                stroke-dashoffset: 0;
+                /* stroke-width: 20px; */
+            }
+
+            70% {
+                stroke-dashoffset: 0;
+                /* stroke-width: 20px; */
+            }
+
+            90% {
+                stroke-dashoffset: 1000;
+                /* stroke-width: 0px; */
+            }
+
+            100% {
+                stroke-dashoffset: 1000;
+                /* stroke-width: 0px; */
+            }
+        }
+    </style>
 </head>
 
 <body style="display:flex" id="dash-body">
     <div class="dash-loader" id="loader" style="z-index:10; width:100%; height:100%">
         <div class="dash-loader-container">
-            <svg viewBox="0 0 1000 350" preserveAspectRatio="xMidYMid meet" xmlns="http://www.w3.org/2000/svg"
-                xmlns:xlink="http://www.w3.org/1999/xlink">
-                <path class="dash-h-path" fill-rule="evenodd" stroke="rgb(0, 0, 0)" stroke-width="35px"
-                    stroke-linecap="butt" stroke-linejoin="miter" fill="none"
-                    d="M715.500,18.500 C715.471,31.660 714.944,295.500 714.500,295.500 C714.402,295.500 715.244,280.815 715.500,256.500 C715.946,214.157 715.230,180.785 738.500,156.500 C747.852,146.740 760.202,139.340 773.500,135.500 C787.860,131.353 803.153,131.374 817.500,135.500 C831.597,139.554 844.116,147.176 853.500,157.500 C860.178,164.847 868.127,178.418 872.500,197.500 C876.205,213.669 875.764,225.372 875.500,240.500 C875.182,258.739 876.422,275.258 876.500,293.500 C876.527,299.855 876.527,306.155 876.500,312.500 " />
-                <path class="dash-s-path" fill-rule="evenodd" stroke="rgb(0, 0, 0)" stroke-width="35px"
-                    stroke-linecap="butt" stroke-linejoin="miter" fill="none" d="M478.500,218.500 L659.500,218.500 " />
-                <path class="dash-a-path" fill-rule="evenodd" stroke="rgb(0, 0, 0)" stroke-width="35px"
-                    stroke-linecap="butt" stroke-linejoin="miter" fill="none"
-                    d="M415.500,114.500 C415.289,138.638 414.639,172.181 414.500,186.500 C414.443,192.334 413.099,209.263 410.500,222.500 C406.705,241.826 400.738,255.391 393.500,264.500 C384.452,275.887 372.241,284.599 358.500,289.500 C341.059,295.721 322.262,295.132 305.500,289.500 C288.269,283.710 269.907,271.467 259.500,251.500 C251.662,236.462 249.244,218.558 252.500,200.500 C255.577,183.436 263.540,167.965 275.500,156.500 C284.223,148.138 296.476,140.618 313.500,136.500 C328.570,132.855 340.519,133.485 349.500,135.500 C361.011,138.082 372.777,143.861 383.500,153.500 C391.643,160.820 398.714,170.309 404.500,183.500 C417.205,212.466 414.550,240.003 412.500,270.500 C411.558,284.506 410.905,298.271 410.500,312.500 " />
-                <path class="dash-d-path" fill-rule="evenodd" stroke="rgb(0, 0, 0)" stroke-width="35px"
-                    stroke-linecap="butt" stroke-linejoin="miter" fill="none"
-                    d="M196.500,18.500 C195.888,79.462 194.655,160.273 197.500,195.500 C198.117,203.144 199.664,225.773 189.500,246.500 C183.949,257.819 175.192,268.535 163.500,277.500 C147.404,289.842 133.006,294.212 121.500,295.500 C106.618,297.166 92.057,294.673 79.500,288.500 C68.971,283.324 58.384,274.780 49.500,261.500 C39.958,247.237 35.188,230.375 35.500,213.500 C35.760,199.463 39.572,185.692 46.500,173.500 C55.433,157.780 65.945,148.829 75.500,143.500 C85.352,138.005 98.187,134.141 114.500,134.500 C128.982,134.819 143.177,139.076 155.500,146.500 C186.160,164.973 196.208,196.242 197.500,216.500 C197.663,219.061 197.578,222.985 197.500,226.500 C197.092,244.967 195.719,262.030 195.500,280.500 C195.460,283.898 195.500,293.783 195.500,300.500 C195.500,304.834 195.500,309.189 195.500,313.500 " />
+            <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200px"
+                height="200px" viewBox="0 0 250 350">
+                <path class="dash-d-path" fill-rule="evenodd" stroke="#ececec" stroke-width="20px" stroke-linecap="butt"
+                    stroke-linejoin="miter" fill="none"
+                    d="M196.500,18.500 C195.888,79.462 194.655,160.273 197.500,195.500 C198.117,203.144 199.664,225.773 189.500,246.500 C183.949,257.819 175.192,268.535 163.500,277.500 C147.404,289.842 133.006,294.212 121.500,295.500 C106.618,297.166 92.057,294.673 79.500,288.500 C68.970,283.324 58.384,274.780 49.500,261.500 C39.958,247.237 35.188,230.375 35.500,213.500 C35.760,199.463 39.572,185.692 46.500,173.500 C55.433,157.780 65.945,148.829 75.500,143.500 C85.352,138.005 98.187,134.141 114.500,134.500 C128.982,134.819 143.177,139.076 155.500,146.500 C186.160,164.973 196.208,196.242 197.500,216.500 C197.663,219.061 197.578,222.985 197.500,226.500 C197.092,244.967 195.719,262.030 195.500,280.500 C195.460,283.898 195.500,293.783 195.500,300.500 C195.500,304.834 195.500,309.189 195.500,313.500 " />
             </svg>
         </div>
     </div>
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 202cd7b1f..4b046bb1a 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -63,7 +63,7 @@ export class CurrentUserUtils {
                 [this.ficon({
                     ignoreClick: true,
                     icon: "mobile",
-                    backgroundColor: "rgba(0,0,0,0)"
+                    backgroundColor: "transparent"
                 }),
                 this.mobileTextContainer({},
                     [this.mobileButtonText({}, "NEW MOBILE BUTTON"), this.mobileButtonInfo({}, "You can customize this button and make it your own.")])]);
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 245e612b3..97bca110b 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -992,7 +992,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                     <div className="propertiesView-title" style={{ width: this.props.width }}>
                         Presentation
                     </div>
-                    <div className="propertiesView-name">
+                    <div className="propertiesView-name" style={{ borderBottom: 0 }}>
                         {this.editableTitle}
                         <div className="propertiesView-presSelected">
                             <div className="propertiesView-selectedCount">
@@ -1029,7 +1029,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                             {PresBox.Instance.progressivizeDropdown}
                         </div> : null}
                     </div>} */}
-                    {/* {!selectedItem || (!scrollable && !pannable) ? (null) : <div className="propertiesView-presTrails">
+                    {!selectedItem ? (null) : <div className="propertiesView-presTrails">
                         <div className="propertiesView-presTrails-title"
                             onPointerDown={action(() => { this.openSlideOptions = !this.openSlideOptions; })}
                             style={{ backgroundColor: this.openSlideOptions ? "black" : "" }}>
@@ -1041,7 +1041,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                         {this.openSlideOptions ? <div className="propertiesView-presTrails-content">
                             {PresBox.Instance.optionsDropdown}
                         </div> : null}
-                    </div>} */}
+                    </div>}
                     {/* <div className="propertiesView-presTrails">
                         <div className="propertiesView-presTrails-title"
                             onPointerDown={action(() => { this.openAddSlide = !this.openAddSlide; })}
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 7f8f57088..4c0073dcc 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -442,8 +442,8 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                 let docColor = StrCast(doc?._backgroundColor, StrCast(doc?.backgroundColor));
                 if (!docColor) {
                     switch (doc?.type) {
-                        case DocumentType.PRESELEMENT: docColor = TabDocView.darkScheme ? "dimgrey" : ""; break;
-                        case DocumentType.PRES: docColor = TabDocView.darkScheme ? "#3e3e3e" : "black"; break;
+                        case DocumentType.PRESELEMENT: docColor = TabDocView.darkScheme ? "" : ""; break;
+                        case DocumentType.PRES: docColor = TabDocView.darkScheme ? "#3e3e3e" : "white"; break;
                         case DocumentType.FONTICON: docColor = "black"; break;
                         case DocumentType.RTF: docColor = TabDocView.darkScheme ? "#2d2d2d" : "#f1efeb";
                         case DocumentType.LABEL:
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 4f6c5cebe..1bdba7f9e 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -27,6 +27,8 @@ import Waveform from "react-audio-waveform";
 import axios from "axios";
 import { SnappingManager } from "../../util/SnappingManager";
 import { CurrentUserUtils } from "../../util/CurrentUserUtils";
+import { LinkDocPreview } from "./LinkDocPreview";
+import { FormattedTextBoxComment } from "./formattedText/FormattedTextBoxComment";
 
 declare class MediaRecorder {
     // whatever MediaRecorder has
@@ -49,6 +51,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
     _linkPlayDisposer: IReactionDisposer | undefined;
     _reactionDisposer: IReactionDisposer | undefined;
     _scrubbingDisposer: IReactionDisposer | undefined;
+    private _disposers: { [name: string]: IReactionDisposer } = {};
     _ele: HTMLAudioElement | null = null;
     _recorder: any;
     _recordStart = 0;
@@ -106,9 +109,10 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
     }
 
     componentWillUnmount() {
-        this._reactionDisposer?.();
-        this._linkPlayDisposer?.();
-        this._scrubbingDisposer?.();
+        this._disposers.reaction?.();
+        this._disposers.linkPlay?.();
+        this._disposers.scrubbing?.();
+        this._disposers.audioStart?.();
     }
 
     @action
@@ -118,7 +122,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
         }
 
         this.audioState = this.path ? "paused" : undefined;
-        this._linkPlayDisposer = reaction(() => this.layoutDoc.scrollToLinkID,
+        this._disposers.linkPlay = reaction(() => this.layoutDoc.scrollToLinkID,
             scrollLinkId => {
                 if (scrollLinkId) {
                     DocListCast(this.dataDoc.links).filter(l => l[Id] === scrollLinkId).map(l => {
@@ -130,7 +134,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
             }, { fireImmediately: true });
 
         // for play when link is selected
-        this._reactionDisposer = reaction(() => SelectionManager.SelectedDocuments(),
+        this._disposers.reaction = reaction(() => SelectionManager.SelectedDocuments(),
             selected => {
                 const sel = selected.length ? selected[0].props.Document : undefined;
                 let link;
@@ -145,7 +149,22 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
                     this.layoutDoc.playOnSelect && this.recordingStart && !sel && this.pause();
                 }
             });
-        this._scrubbingDisposer = reaction(() => AudioBox._scrubTime, (time) => this.layoutDoc.playOnSelect && this.playFromTime(AudioBox._scrubTime));
+        this._disposers.scrubbing = reaction(() => AudioBox._scrubTime, (time) => this.layoutDoc.playOnSelect && this.playFromTime(AudioBox._scrubTime));
+
+        this._disposers._audioStart = reaction(
+            () => this.Document._audioStart,
+            (audioStart) => {
+                if (audioStart !== undefined) {
+                    if (this.props.renderDepth !== -1 && !LinkDocPreview.TargetDoc && !FormattedTextBoxComment.linkDoc) {
+                        const delay = this._audioRef.current ? 0 : 250; // wait for mainCont and try again to play
+                        const startTime: number = NumCast(this.Document._audioStart);
+                        setTimeout(() => this._audioRef.current && this.playFrom(startTime), delay);
+                        setTimeout(() => { this.Document._currentTimecode = startTime; this.Document._audioStart = undefined; }, 10 + delay);
+                    }
+                }
+            },
+            { fireImmediately: true }
+        );
     }
 
     playLink = (doc: Doc) => {
diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx
index fa58a67b6..dd6e368e8 100644
--- a/src/client/views/nodes/PresBox.tsx
+++ b/src/client/views/nodes/PresBox.tsx
@@ -117,7 +117,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         if (Doc.UserDoc().activePresentation = this.rootDoc) runInAction(() => PresBox.Instance = this);
         if (!this.presElement) { // create exactly one presElmentBox template to use by any and all presentations.
             Doc.UserDoc().presElement = new PrefetchProxy(Docs.Create.PresElementBoxDocument({
-                title: "pres element template", type: DocumentType.PRESELEMENT, backgroundColor: "transparent", _xMargin: 0, isTemplateDoc: true, isTemplateForField: "data"
+                title: "pres element template", type: DocumentType.PRESELEMENT, _xMargin: 0, isTemplateDoc: true, isTemplateForField: "data"
             }));
             // this script will be called by each presElement to get rendering-specific info that the PresBox knows about but which isn't written to the PresElement
             // this is a design choice -- we could write this data to the presElements which would require a reaction to keep it up to date, and it would prevent
@@ -191,7 +191,9 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
 
     // 'Play on next' for audio or video therefore first navigate to the audio/video before it should be played
     nextAudioVideo = (targetDoc: Doc, activeItem: Doc) => {
-        if (targetDoc.type === DocumentType.AUDIO) AudioBox.Instance.playFrom(NumCast(activeItem.presStartTime));
+        if (targetDoc.type === DocumentType.AUDIO) {
+            targetDoc._audioStart = NumCast(activeItem.presStartTime);
+        }
         // if (targetDoc.type === DocumentType.VID) { VideoBox.Instance.Play() };
         activeItem.playNow = false;
     }
@@ -201,13 +203,12 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         const nextSelected = this.itemIndex + 1;
         this.gotoDocument(nextSelected);
 
-        // const targetNext = Cast(activeNext.presentationTargetDoc, Doc, null);
+        const targetNext = Cast(activeNext.presentationTargetDoc, Doc, null);
         // If next slide is audio / video 'Play automatically' then the next slide should be played
-        // if (activeNext && (targetNext.type === DocumentType.AUDIO || targetNext.type === DocumentType.VID) && activeNext.playAuto) {
-        //     console.log('play next automatically');
-        //     if (targetNext.type === DocumentType.AUDIO) AudioBox.Instance.playFrom(NumCast(activeNext.presStartTime));
-        //     // if (targetNext.type === DocumentType.VID) { VideoBox.Instance.Play() };
-        // } else if (targetNext.type === DocumentType.AUDIO || targetNext.type === DocumentType.VID) { activeNext.playNow = true; console.log('play next after it is navigated to'); }
+        if (activeNext && (targetNext.type === DocumentType.AUDIO || targetNext.type === DocumentType.VID) && activeNext.playAuto) {
+            if (targetNext.type === DocumentType.AUDIO) targetNext._audioStart = NumCast(activeNext.presStartTime);
+            // if (targetNext.type === DocumentType.VID) { VideoBox.Instance.Play() };
+        } else if (targetNext.type === DocumentType.AUDIO || targetNext.type === DocumentType.VID) { activeNext.playNow = true; console.log('play next after it is navigated to'); }
     }
 
     // Called when the user activates 'next' - to move to the next part of the pres. trail
@@ -229,11 +230,10 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         } else if (this.childDocs[this.itemIndex + 1] === undefined && this.layoutDoc.presLoop) {
             // Case 4: Last slide and presLoop is toggled ON
             this.gotoDocument(0);
+        } else if ((targetDoc.type === DocumentType.AUDIO || targetDoc.type === DocumentType.VID) && !activeItem.playAuto && activeItem.playNow && this.layoutDoc.presStatus !== PresStatus.Autoplay) {
+            // Case 2: 'Play on next' for audio or video therefore first navigate to the audio/video before it should be played
+            this.nextAudioVideo(targetDoc, activeItem);
         }
-        // else if ((targetDoc.type === DocumentType.AUDIO || targetDoc.type === DocumentType.VID) && !activeItem.playAuto && activeItem.playNow && this.layoutDoc.presStatus !== PresStatus.Autoplay) {
-        //     // Case 2: 'Play on next' for audio or video therefore first navigate to the audio/video before it should be played
-        //     this.nextAudioVideo(targetDoc, activeItem);
-        // } 
     }
 
     // Called when the user activates 'back' - to move to the previous part of the pres. trail
@@ -1927,7 +1927,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                     <FontAwesomeIcon className={`dropdown ${this.newDocumentTools ? "active" : ""}`} icon={"angle-down"} />
                 </div></Tooltip> */}
                 <Tooltip title={<><div className="dash-tooltip">{"View paths"}</div></>}>
-                    <div style={{ opacity: this.childDocs.length > 1 ? 1 : 0.3, color: this._pathBoolean ? PresColor.DarkBlue : 'white', width: isMini ? "100%" : undefined }} className={"toolbar-button"} onClick={this.childDocs.length > 1 ? this.viewPaths : undefined}>
+                    <div style={{ opacity: this.childDocs.length > 1 && this.layoutDoc.presCollection ? 1 : 0.3, color: this._pathBoolean ? PresColor.DarkBlue : 'white', width: isMini ? "100%" : undefined }} className={"toolbar-button"} onClick={this.childDocs.length > 1 && this.layoutDoc.presCollection ? this.viewPaths : undefined}>
                         <FontAwesomeIcon icon={"exchange-alt"} />
                     </div>
                 </Tooltip>
diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx
index 8d4bd4b8b..49049b805 100644
--- a/src/client/views/presentationview/PresElementBox.tsx
+++ b/src/client/views/presentationview/PresElementBox.tsx
@@ -305,10 +305,12 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
                 onPointerUp={this.headerUp}
             >
                 {miniView ?
+                    // when width is LESS than 110 px 
                     <div className={`presItem-miniSlide ${isSelected ? "active" : ""}`} ref={miniView ? this._dragRef : null}>
                         {`${this.indexInPres + 1}.`}
                     </div>
                     :
+                    // when width is MORE than 110 px 
                     <div className="presItem-number">
                         {`${this.indexInPres + 1}.`}
                     </div>}
-- 
cgit v1.2.3-70-g09d2


From 534a4e81e84adbd46b629731ac3ca7d3ea41a670 Mon Sep 17 00:00:00 2001
From: geireann <60007097+geireann@users.noreply.github.com>
Date: Sun, 29 Nov 2020 11:15:30 +0800
Subject: temporal media updates for pres. trails

---
 deploy/index.html                                  |   4 +-
 src/client/views/MainView.tsx                      |   8 +-
 src/client/views/PropertiesView.tsx                |   8 +-
 src/client/views/nodes/AudioBox.tsx                |  22 +-
 src/client/views/nodes/PresBox.scss                |  83 +++-
 src/client/views/nodes/PresBox.tsx                 | 323 +++++++++-----
 src/client/views/nodes/VideoBox.tsx                |  51 ++-
 .../views/presentationview/PresElementBox.scss     |  41 +-
 .../views/presentationview/PresElementBox.tsx      |   3 +-
 .../views/presentationview/PresProperties.tsx      | 492 +++++++++++++++++++++
 10 files changed, 901 insertions(+), 134 deletions(-)
 create mode 100644 src/client/views/presentationview/PresProperties.tsx

(limited to 'src/client/views/PropertiesView.tsx')

diff --git a/deploy/index.html b/deploy/index.html
index af67ac301..beb7dd205 100644
--- a/deploy/index.html
+++ b/deploy/index.html
@@ -14,8 +14,8 @@
             justify-content: center;
             background-color: #AEDDF8;
             z-index: 10;
-            width: 100%;
-            height: 100%;
+            width: 100vw;
+            height: 100vh;
         }
 
         .dash-loader-container {
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 03d2e33df..b1e008dad 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -87,11 +87,11 @@ export class MainView extends React.Component {
     componentDidMount() {
         document.getElementById("root")?.addEventListener("scroll", e => ((ele) => ele.scrollLeft = ele.scrollTop = 0)(document.getElementById("root")!));
         const ele = document.getElementById("loader");
+
         if (ele) {
-            setTimeout(() => {
-                // remove from DOM
-                ele.outerHTML = '';
-            }, 0);
+            // remove from DOM
+            setTimeout(() => { ele.style.opacity = "0"; }, 0);
+            setTimeout(() => ele.outerHTML = '', 10000);
         }
         new InkStrokeProperties();
         this._sidebarContent.proto = undefined;
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 97bca110b..c656a020e 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -1007,7 +1007,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                         <div className="propertiesView-presTrails-title"
                             onPointerDown={action(() => { this.openPresTransitions = !this.openPresTransitions; })}
                             style={{ backgroundColor: this.openPresTransitions ? "black" : "" }}>
-                            &nbsp; <FontAwesomeIcon icon={"rocket"} /> &nbsp; Transitions
+                            &nbsp; <FontAwesomeIcon style={{ alignSelf: "center" }} icon={"rocket"} /> &nbsp; Transitions
                         <div className="propertiesView-presTrails-title-icon">
                                 <FontAwesomeIcon icon={this.openPresTransitions ? "caret-down" : "caret-right"} size="lg" color="white" />
                             </div>
@@ -1029,17 +1029,17 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                             {PresBox.Instance.progressivizeDropdown}
                         </div> : null}
                     </div>} */}
-                    {!selectedItem ? (null) : <div className="propertiesView-presTrails">
+                    {!selectedItem || (type !== DocumentType.VID && type !== DocumentType.AUDIO) ? (null) : <div className="propertiesView-presTrails">
                         <div className="propertiesView-presTrails-title"
                             onPointerDown={action(() => { this.openSlideOptions = !this.openSlideOptions; })}
                             style={{ backgroundColor: this.openSlideOptions ? "black" : "" }}>
-                            &nbsp; <FontAwesomeIcon icon={"cog"} /> &nbsp; {scrollable ? "Scroll options" : "Pan options"}
+                            &nbsp; <FontAwesomeIcon style={{ alignSelf: "center" }} icon={type === DocumentType.AUDIO ? "file-audio" : "file-video"} /> &nbsp; {type === DocumentType.AUDIO ? "Audio Options" : "Video Options"}
                             <div className="propertiesView-presTrails-title-icon">
                                 <FontAwesomeIcon icon={this.openSlideOptions ? "caret-down" : "caret-right"} size="lg" color="white" />
                             </div>
                         </div>
                         {this.openSlideOptions ? <div className="propertiesView-presTrails-content">
-                            {PresBox.Instance.optionsDropdown}
+                            {PresBox.Instance.mediaOptionsDropdown}
                         </div> : null}
                     </div>}
                     {/* <div className="propertiesView-presTrails">
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 1bdba7f9e..2527a2db1 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -48,9 +48,9 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
     static RangeScript: ScriptField;
     static LabelScript: ScriptField;
 
-    _linkPlayDisposer: IReactionDisposer | undefined;
-    _reactionDisposer: IReactionDisposer | undefined;
-    _scrubbingDisposer: IReactionDisposer | undefined;
+    // _linkPlayDisposer: IReactionDisposer | undefined;
+    // _reactionDisposer: IReactionDisposer | undefined;
+    // _scrubbingDisposer: IReactionDisposer | undefined;
     private _disposers: { [name: string]: IReactionDisposer } = {};
     _ele: HTMLAudioElement | null = null;
     _recorder: any;
@@ -151,7 +151,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
             });
         this._disposers.scrubbing = reaction(() => AudioBox._scrubTime, (time) => this.layoutDoc.playOnSelect && this.playFromTime(AudioBox._scrubTime));
 
-        this._disposers._audioStart = reaction(
+        this._disposers.audioStart = reaction(
             () => this.Document._audioStart,
             (audioStart) => {
                 if (audioStart !== undefined) {
@@ -165,6 +165,20 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
             },
             { fireImmediately: true }
         );
+
+        this._disposers.audioStop = reaction(
+            () => this.Document._audioStop,
+            (audioStop) => {
+                if (audioStop !== undefined) {
+                    if (this.props.renderDepth !== -1 && !LinkDocPreview.TargetDoc && !FormattedTextBoxComment.linkDoc) {
+                        const delay = this._audioRef.current ? 0 : 250; // wait for mainCont and try again to play
+                        setTimeout(() => this._audioRef.current && this.pause(), delay);
+                        setTimeout(() => { this.Document._audioStop = undefined; }, 10 + delay);
+                    }
+                }
+            },
+            { fireImmediately: true }
+        );
     }
 
     playLink = (doc: Doc) => {
diff --git a/src/client/views/nodes/PresBox.scss b/src/client/views/nodes/PresBox.scss
index 56b3b0593..6579dbf41 100644
--- a/src/client/views/nodes/PresBox.scss
+++ b/src/client/views/nodes/PresBox.scss
@@ -127,6 +127,17 @@ $light-background: #ececec;
     opacity: 0.8;
 }
 
+.presBox-radioButtons {
+    background-color: rgba(0, 0, 0, 0.1);
+
+    .checkbox-container {
+        margin-left: 10px;
+        display: inline-flex;
+        height: 20px;
+        align-items: center;
+    }
+}
+
 .presBox-ribbon {
     position: relative;
     display: inline;
@@ -209,6 +220,42 @@ $light-background: #ececec;
     }
 
     @media screen and (-webkit-min-device-pixel-ratio:0) {
+
+        .multiThumb-slider {
+            display: grid;
+            background-color: $light-background;
+            height: 10px;
+            border-radius: 10px;
+            overflow: hidden;
+
+            .toolbar-slider {
+                margin-top: 0px;
+                background: none;
+                -webkit-appearance: none;
+                pointer-events: none;
+            }
+
+            .toolbar-slider.start::-webkit-slider-thumb {
+                width: 10px;
+                pointer-events: auto;
+                -webkit-appearance: none;
+                height: 10px;
+                cursor: ew-resize;
+                background: $dark-blue;
+                box-shadow: -100vw 0 0 100vw $light-background;
+            }
+
+            .toolbar-slider.end::-webkit-slider-thumb {
+                width: 10px;
+                pointer-events: auto;
+                -webkit-appearance: none;
+                height: 10px;
+                cursor: ew-resize;
+                background: $dark-blue;
+                box-shadow: -100vw 0 0 100vw $light-blue;
+            }
+        }
+
         .toolbar-slider {
             margin-top: 5px;
             position: relative;
@@ -219,7 +266,7 @@ $light-background: #ececec;
             height: 10px;
             border-radius: 10px;
             -webkit-appearance: none;
-            background-color: #ececec;
+            background-color: $light-background;
         }
 
         .toolbar-slider:focus {
@@ -234,14 +281,44 @@ $light-background: #ececec;
 
         .toolbar-slider::-webkit-slider-thumb {
             width: 10px;
+            pointer-events: auto;
             -webkit-appearance: none;
             height: 10px;
             cursor: ew-resize;
-            background: #5b9ddd;
-            box-shadow: -100vw 0 0 100vw #aedef8;
+            background: $dark-blue;
+            box-shadow: -100vw 0 0 100vw $light-blue;
+        }
+
+        .presBox-checkbox {
+            -webkit-appearance: none;
+            -webkit-user-select: none;
+            -moz-user-select: none;
+            -ms-user-select: none;
+            user-select: none;
+            margin: 0;
+            margin-right: 3px;
+            border-radius: 100%;
+            height: 15px;
+            width: 15px;
+            cursor: pointer;
+            background: $light-background;
+        }
+
+        .presBox-checkbox:focus {
+            outline: none;
+        }
+
+        .presBox-checkbox:hover {
+            background: #c0c0c0;
+        }
+
+        .presBox-checkbox:checked {
+            background: $light-blue;
         }
     }
 
+
+
     .slider-headers {
         position: relative;
         display: grid;
diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx
index 1405016ae..9fb07040d 100644
--- a/src/client/views/nodes/PresBox.tsx
+++ b/src/client/views/nodes/PresBox.tsx
@@ -24,7 +24,6 @@ import { CollectionDockingView } from "../collections/CollectionDockingView";
 import { CollectionView, CollectionViewType } from "../collections/CollectionView";
 import { TabDocView } from "../collections/TabDocView";
 import { ViewBoxBaseComponent } from "../DocComponent";
-import { AudioBox } from "./AudioBox";
 import { CollectionFreeFormDocumentView } from "./CollectionFreeFormDocumentView";
 import { FieldView, FieldViewProps } from './FieldView';
 import "./PresBox.scss";
@@ -193,6 +192,10 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
     nextAudioVideo = (targetDoc: Doc, activeItem: Doc) => {
         if (targetDoc.type === DocumentType.AUDIO) {
             targetDoc._audioStart = NumCast(activeItem.presStartTime);
+
+        } else if (targetDoc.type === DocumentType.VID) {
+            targetDoc._currentTimecode = NumCast(activeItem.presStartTime);
+            setTimeout(() => targetDoc._videoStart = true, 0);
         }
         // if (targetDoc.type === DocumentType.VID) { VideoBox.Instance.Play() };
         activeItem.playNow = false;
@@ -214,7 +217,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         // If next slide is audio / video 'Play automatically' then the next slide should be played
         if (activeNext && (targetNext.type === DocumentType.AUDIO || targetNext.type === DocumentType.VID) && activeNext.playAuto) {
             if (targetNext.type === DocumentType.AUDIO) targetNext._audioStart = NumCast(activeNext.presStartTime);
-            // if (targetNext.type === DocumentType.VID) { VideoBox.Instance.Play() };
         } else if (targetNext.type === DocumentType.AUDIO || targetNext.type === DocumentType.VID) { activeNext.playNow = true; console.log('play next after it is navigated to'); }
     }
 
@@ -1071,6 +1073,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
     @computed get transitionDropdown() {
         const activeItem: Doc = this.activeItem;
         const targetDoc: Doc = this.targetDoc;
+        const type: DocumentType = targetDoc.type;
         const isPresCollection: boolean = (targetDoc === this.layoutDoc.presCollection);
         const isPinWithView: boolean = BoolCast(activeItem.presPinView);
         if (activeItem && targetDoc) {
@@ -1137,7 +1140,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                             {isPresCollection ? (null) : <Tooltip title={<><div className="dash-tooltip">{"Hide after presented"}</div></>}><div className={`ribbon-toggle ${activeItem.presHideAfter ? "active" : ""}`} onClick={() => this.updateHideAfter(activeItem)}>Hide after</div></Tooltip>}
                             <Tooltip title={<><div className="dash-tooltip">{"Open document in a new tab"}</div></>}><div className="ribbon-toggle" style={{ backgroundColor: activeItem.openDocument ? PresColor.LightBlue : "" }} onClick={() => this.updateOpenDoc(activeItem)}>Open</div></Tooltip>
                         </div>
-                        <div className="ribbon-doubleButton" >
+                        {(type === DocumentType.AUDIO || type === DocumentType.VID) ? (null) : <div className="ribbon-doubleButton" >
                             <div className="presBox-subheading">Slide Duration</div>
                             <div className="ribbon-property">
                                 <input className="presBox-input"
@@ -1152,7 +1155,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                                     <FontAwesomeIcon icon={"caret-down"} />
                                 </div>
                             </div>
-                        </div>
+                        </div>}
                         <input type="range" step="0.1" min="0.1" max="20" value={duration}
                             style={{ display: targetDoc.type === DocumentType.AUDIO ? "none" : "block" }}
                             className={"toolbar-slider"} id="duration-slider"
@@ -1235,20 +1238,233 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
             }
         });
     }
-    @computed get optionsDropdown() {
+
+    @computed get presPinViewOptionsDropdown() {
         const activeItem: Doc = this.activeItem;
         const targetDoc: Doc = this.targetDoc;
         const presPinWithViewIcon = <img src="/assets/pinWithView.png" style={{ margin: "auto", width: 16, filter: 'invert(1)' }} />;
+        return (
+            <>
+                {this.panable || this.scrollable || this.targetDoc.type === DocumentType.COMPARISON ? 'Pinned view' : (null)}
+                <div className="ribbon-doubleButton">
+                    <Tooltip title={<><div className="dash-tooltip">{activeItem.presPinView ? "Turn off pin with view" : "Turn on pin with view"}</div></>}><div className="ribbon-toggle" style={{ width: 20, padding: 0, backgroundColor: activeItem.presPinView ? PresColor.LightBlue : "" }}
+                        onClick={() => {
+                            activeItem.presPinView = !activeItem.presPinView;
+                            targetDoc.presPinView = activeItem.presPinView;
+                            if (activeItem.presPinView) {
+                                if (targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.RTF || targetDoc.type === DocumentType.WEB || targetDoc._viewType === CollectionViewType.Stacking) {
+                                    const scroll = targetDoc._scrollTop;
+                                    activeItem.presPinView = true;
+                                    activeItem.presPinViewScroll = scroll;
+                                } else if (targetDoc.type === DocumentType.VID) {
+                                    activeItem.presPinTimecode = targetDoc._currentTimecode;
+                                } else if ((targetDoc.type === DocumentType.COL && targetDoc._viewType === CollectionViewType.Freeform) || targetDoc.type === DocumentType.IMG) {
+                                    const x = targetDoc._panX;
+                                    const y = targetDoc._panY;
+                                    const scale = targetDoc._viewScale;
+                                    activeItem.presPinView = true;
+                                    activeItem.presPinViewX = x;
+                                    activeItem.presPinViewY = y;
+                                    activeItem.presPinViewScale = scale;
+                                } else if (targetDoc.type === DocumentType.COMPARISON) {
+                                    const width = targetDoc._clipWidth;
+                                    activeItem.presPinClipWidth = width;
+                                    activeItem.presPinView = true;
+                                }
+                            }
+                        }}>{presPinWithViewIcon}</div></Tooltip>
+                    {activeItem.presPinView ? <Tooltip title={<><div className="dash-tooltip">{"Update the pinned view with the view of the selected document"}</div></>}><div className="ribbon-button"
+                        onClick={() => {
+                            if (targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.WEB || targetDoc.type === DocumentType.RTF) {
+                                const scroll = targetDoc._scrollTop;
+                                activeItem.presPinViewScroll = scroll;
+                            } else if (targetDoc.type === DocumentType.VID) {
+                                activeItem.presPinTimecode = targetDoc._currentTimecode;
+                            } else if (targetDoc.type === DocumentType.COMPARISON) {
+                                const clipWidth = targetDoc._clipWidth;
+                                activeItem.presPinClipWidth = clipWidth;
+                            } else {
+                                const x = targetDoc._panX;
+                                const y = targetDoc._panY;
+                                const scale = targetDoc._viewScale;
+                                activeItem.presPinViewX = x;
+                                activeItem.presPinViewY = y;
+                                activeItem.presPinViewScale = scale;
+                            }
+                        }}>Update</div></Tooltip> : (null)}
+                </div>
+            </>
+        );
+    }
+
+    @computed get panOptionsDropdown() {
+        const activeItem: Doc = this.activeItem;
+        const targetDoc: Doc = this.targetDoc;
+        return (
+            <>
+                {this.panable ? <div style={{ display: activeItem.presPinView ? "block" : "none" }}>
+                    <div className="ribbon-doubleButton" style={{ marginRight: 10 }}>
+                        <div className="presBox-subheading">Pan X</div>
+                        <div className="ribbon-property" style={{ paddingRight: 0, paddingLeft: 0 }}>
+                            <input className="presBox-input"
+                                style={{ textAlign: 'left', width: 50 }}
+                                type="number" value={NumCast(activeItem.presPinViewX)}
+                                onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { const val = e.target.value; activeItem.presPinViewX = Number(val); })} />
+                        </div>
+                    </div>
+                    <div className="ribbon-doubleButton" style={{ marginRight: 10 }}>
+                        <div className="presBox-subheading">Pan Y</div>
+                        <div className="ribbon-property" style={{ paddingRight: 0, paddingLeft: 0 }}>
+                            <input className="presBox-input"
+                                style={{ textAlign: 'left', width: 50 }}
+                                type="number" value={NumCast(activeItem.presPinViewY)}
+                                onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { const val = e.target.value; activeItem.presPinViewY = Number(val); })} />
+                        </div>
+                    </div>
+                    <div className="ribbon-doubleButton" style={{ marginRight: 10 }}>
+                        <div className="presBox-subheading">Scale</div>
+                        <div className="ribbon-property" style={{ paddingRight: 0, paddingLeft: 0 }}>
+                            <input className="presBox-input"
+                                style={{ textAlign: 'left', width: 50 }}
+                                type="number" value={NumCast(activeItem.presPinViewScale)}
+                                onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { const val = e.target.value; activeItem.presPinViewScale = Number(val); })} />
+                        </div>
+                    </div>
+                </div> : (null)}
+            </>
+        );
+    }
+
+    @computed get scrollOptionsDropdown() {
+        const activeItem: Doc = this.activeItem;
+        const targetDoc: Doc = this.targetDoc;
+        return (
+            <>
+                {this.scrollable ? <div style={{ display: activeItem.presPinView ? "block" : "none" }}>
+                    <div className="ribbon-doubleButton" style={{ marginRight: 10 }}>
+                        <div className="presBox-subheading">Scroll</div>
+                        <div className="ribbon-property" style={{ paddingRight: 0, paddingLeft: 0 }}>
+                            <input className="presBox-input"
+                                style={{ textAlign: 'left', width: 50 }}
+                                type="number" value={NumCast(activeItem.presPinViewScroll)}
+                                onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { const val = e.target.value; activeItem.presPinViewScroll = Number(val); })} />
+                        </div>
+                    </div>
+                </div> : (null)}
+            </>
+        );
+    }
+
+    @computed get mediaOptionsDropdown() {
+        const activeItem: Doc = this.activeItem;
+        const targetDoc: Doc = this.targetDoc;
         if (activeItem && targetDoc) {
             return (
                 <div>
                     <div className={'presBox-ribbon'} onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
-                        <div className="ribbon-box">
+                        <div>
+                            <div className="presBox-subheading">Start playing:</div>
+                            <div className="presBox-radioButtons">
+                                <div className="checkbox-container">
+                                    <input className="presBox-checkbox"
+                                        type="checkbox"
+                                        onChange={() => activeItem.mediaPlay = "manual"}
+                                        checked={activeItem.mediaPlay === "manual"}
+                                    />
+                                    <div>Start manually</div>
+                                </div>
+                                <div className="checkbox-container">
+                                    <input className="presBox-checkbox"
+                                        type="checkbox"
+                                        onChange={() => activeItem.mediaPlay = "auto"}
+                                        checked={activeItem.mediaPlay === "auto"}
+                                    />
+                                    <div>Play with slide</div>
+                                </div>
+                                <div className="checkbox-container">
+                                    <input className="presBox-checkbox"
+                                        type="checkbox"
+                                        onChange={() => activeItem.mediaPlay = "onClick"}
+                                        checked={activeItem.mediaPlay === "onClick"}
+                                    />
+                                    <div>Play on click</div>
+                                </div>
+                            </div>
+                            <div className="presBox-subheading">Stop playing:</div>
+                            <div className="presBox-radioButtons">
+                                <div className="checkbox-container">
+                                    <input className="presBox-checkbox"
+                                        type="checkbox"
+                                        onChange={() => activeItem.mediaStop = "manual"}
+                                        checked={activeItem.mediaStop === "manual"}
+                                    />
+                                    <div>Stop manually</div>
+                                </div>
+                                <div className="checkbox-container">
+                                    <input className="presBox-checkbox"
+                                        type="checkbox"
+                                        onChange={() => activeItem.mediaStop = "afterCurrent"}
+                                        checked={activeItem.mediaStop === "afterCurrent"}
+                                    />
+                                    <div>After current slide</div>
+                                </div>
+                                <div className="checkbox-container">
+                                    <input className="presBox-checkbox"
+                                        type="checkbox"
+                                        onChange={() => activeItem.mediaStop = "afterSlide"}
+                                        checked={activeItem.mediaStop === "afterSlide"}
+                                    />
+                                    <div>After slide
+                                    {activeItem.mediaStop !== "afterSlide" ?
+                                            (null)
+                                            :
+                                            <div className="presBox-dropdown" onClick={action(e => { e.stopPropagation(); this.openMovementDropdown = !this.openMovementDropdown; })} style={{ borderBottomLeftRadius: this.openMovementDropdown ? 0 : 5, border: this.openMovementDropdown ? `solid 2px ${PresColor.DarkBlue}` : 'solid 1px black' }}>
+                                                {this.setMovementName(activeItem.presMovement, activeItem)}
+                                                <FontAwesomeIcon className='presBox-dropdownIcon' style={{ gridColumn: 2, color: this.openMovementDropdown ? PresColor.DarkBlue : 'black' }} icon={"angle-down"} />
+                                                <div className={'presBox-dropdownOptions'} id={'presBoxMovementDropdown'} onPointerDown={e => e.stopPropagation()} style={{ display: this.openMovementDropdown ? "grid" : "none" }}>
+                                                    <div className={`presBox-dropdownOption ${activeItem.presMovement === PresMovement.None ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.None)}>None</div>
+                                                    <div className={`presBox-dropdownOption ${activeItem.presMovement === PresMovement.Zoom ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.Zoom)}>Pan {"&"} Zoom</div>
+                                                    <div className={`presBox-dropdownOption ${activeItem.presMovement === PresMovement.Pan ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.Pan)}>Pan</div>
+                                                    <div className={`presBox-dropdownOption ${activeItem.presMovement === PresMovement.Jump ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.Jump)}>Jump cut</div>
+                                                </div>
+                                            </div>}
+                                    </div>
+                                </div>
+                            </div>
+                            <div className="presBox-subheading">Range:</div>
+                            <div className="multiThumb-slider">
+                                <input type="range" step="0.1" min="0" max={NumCast(activeItem.duration)} value={NumCast(activeItem.presEndTime)}
+                                    style={{ gridColumn: 1, gridRow: 1 }}
+                                    className={`toolbar-slider ${"end"}`}
+                                    id="toolbar-slider"
+                                    onPointerDown={() => this._batch = UndoManager.StartBatch("presEndTime")}
+                                    onPointerUp={() => this._batch?.end()}
+                                    onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
+                                        e.stopPropagation();
+                                        activeItem.presEndTime = Number(e.target.value);
+                                    }} />
+                                <input type="range" step="0.1" min="0" max={NumCast(activeItem.duration)} value={NumCast(activeItem.presStartTime)}
+                                    style={{ gridColumn: 1, gridRow: 1 }}
+                                    className={`toolbar-slider ${"start"}`}
+                                    id="toolbar-slider"
+                                    onPointerDown={() => this._batch = UndoManager.StartBatch("presEndTime")}
+                                    onPointerUp={() => this._batch?.end()}
+                                    onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
+                                        e.stopPropagation();
+                                        activeItem.presStartTime = Number(e.target.value);
+                                    }} />
+                            </div>
+                            <div className={`slider-headers ${activeItem.presMovement === PresMovement.Pan || activeItem.presMovement === PresMovement.Zoom ? "" : "none"}`}>
+                                <div className="slider-text">0 s</div>
+                                <div className="slider-text"></div>
+                                <div className="slider-text">{Math.round(NumCast(activeItem.duration))} s</div>
+                            </div>
+                        </div>
+                        {/* <div className="ribbon-box">
                             <div className="ribbon-doubleButton" style={{ display: targetDoc.type === DocumentType.AUDIO ? "inline-flex" : "none" }}>
                                 <div className="ribbon-toggle" style={{ backgroundColor: activeItem.playAuto ? PresColor.LightBlue : "" }} onClick={() => activeItem.playAuto = !activeItem.playAuto}>Play automatically</div>
                                 <div className="ribbon-toggle" style={{ display: "flex", backgroundColor: activeItem.playAuto ? "" : PresColor.LightBlue }} onClick={() => activeItem.playAuto = !activeItem.playAuto}>Play on next</div>
                             </div>
-                            {/* {targetDoc.type === DocumentType.VID ? <div className="ribbon-toggle" style={{ backgroundColor: activeItem.presVidFullScreen ? PresColor.LightBlue : "" }} onClick={() => activeItem.presVidFullScreen = !activeItem.presVidFullScreen}>Full screen</div> : (null)} */}
                             {targetDoc.type === DocumentType.AUDIO ? <div className="ribbon-doubleButton" style={{ marginRight: 10 }}>
                                 <div className="presBox-subheading">Start time</div>
                                 <div className="ribbon-property" style={{ paddingRight: 0, paddingLeft: 0 }}>
@@ -1267,98 +1483,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                                         onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { const val = e.target.value; activeItem.presEndTime = Number(val); })} />
                                 </div>
                             </div> : (null)}
-                            {this.panable || this.scrollable || this.targetDoc.type === DocumentType.COMPARISON ? 'Pinned view' : (null)}
-                            <div className="ribbon-doubleButton">
-                                <Tooltip title={<><div className="dash-tooltip">{activeItem.presPinView ? "Turn off pin with view" : "Turn on pin with view"}</div></>}><div className="ribbon-toggle" style={{ width: 20, padding: 0, backgroundColor: activeItem.presPinView ? PresColor.LightBlue : "" }}
-                                    onClick={() => {
-                                        activeItem.presPinView = !activeItem.presPinView;
-                                        targetDoc.presPinView = activeItem.presPinView;
-                                        if (activeItem.presPinView) {
-                                            if (targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.RTF || targetDoc.type === DocumentType.WEB || targetDoc._viewType === CollectionViewType.Stacking) {
-                                                const scroll = targetDoc._scrollTop;
-                                                activeItem.presPinView = true;
-                                                activeItem.presPinViewScroll = scroll;
-                                            } else if (targetDoc.type === DocumentType.VID) {
-                                                activeItem.presPinTimecode = targetDoc._currentTimecode;
-                                            } else if ((targetDoc.type === DocumentType.COL && targetDoc._viewType === CollectionViewType.Freeform) || targetDoc.type === DocumentType.IMG) {
-                                                const x = targetDoc._panX;
-                                                const y = targetDoc._panY;
-                                                const scale = targetDoc._viewScale;
-                                                activeItem.presPinView = true;
-                                                activeItem.presPinViewX = x;
-                                                activeItem.presPinViewY = y;
-                                                activeItem.presPinViewScale = scale;
-                                            } else if (targetDoc.type === DocumentType.COMPARISON) {
-                                                const width = targetDoc._clipWidth;
-                                                activeItem.presPinClipWidth = width;
-                                                activeItem.presPinView = true;
-                                            }
-                                        }
-                                    }}>{presPinWithViewIcon}</div></Tooltip>
-                                {activeItem.presPinView ? <Tooltip title={<><div className="dash-tooltip">{"Update the pinned view with the view of the selected document"}</div></>}><div className="ribbon-button"
-                                    onClick={() => {
-                                        if (targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.WEB || targetDoc.type === DocumentType.RTF) {
-                                            const scroll = targetDoc._scrollTop;
-                                            activeItem.presPinViewScroll = scroll;
-                                        } else if (targetDoc.type === DocumentType.VID) {
-                                            activeItem.presPinTimecode = targetDoc._currentTimecode;
-                                        } else if (targetDoc.type === DocumentType.COMPARISON) {
-                                            const clipWidth = targetDoc._clipWidth;
-                                            activeItem.presPinClipWidth = clipWidth;
-                                        } else {
-                                            const x = targetDoc._panX;
-                                            const y = targetDoc._panY;
-                                            const scale = targetDoc._viewScale;
-                                            activeItem.presPinViewX = x;
-                                            activeItem.presPinViewY = y;
-                                            activeItem.presPinViewScale = scale;
-                                        }
-                                    }}>Update</div></Tooltip> : (null)}
-                            </div>
-                            {this.panable ? <div style={{ display: activeItem.presPinView ? "block" : "none" }}>
-                                <div className="ribbon-doubleButton" style={{ marginRight: 10 }}>
-                                    <div className="presBox-subheading">Pan X</div>
-                                    <div className="ribbon-property" style={{ paddingRight: 0, paddingLeft: 0 }}>
-                                        <input className="presBox-input"
-                                            style={{ textAlign: 'left', width: 50 }}
-                                            type="number" value={NumCast(activeItem.presPinViewX)}
-                                            onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { const val = e.target.value; activeItem.presPinViewX = Number(val); })} />
-                                    </div>
-                                </div>
-                                <div className="ribbon-doubleButton" style={{ marginRight: 10 }}>
-                                    <div className="presBox-subheading">Pan Y</div>
-                                    <div className="ribbon-property" style={{ paddingRight: 0, paddingLeft: 0 }}>
-                                        <input className="presBox-input"
-                                            style={{ textAlign: 'left', width: 50 }}
-                                            type="number" value={NumCast(activeItem.presPinViewY)}
-                                            onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { const val = e.target.value; activeItem.presPinViewY = Number(val); })} />
-                                    </div>
-                                </div>
-                                <div className="ribbon-doubleButton" style={{ marginRight: 10 }}>
-                                    <div className="presBox-subheading">Scale</div>
-                                    <div className="ribbon-property" style={{ paddingRight: 0, paddingLeft: 0 }}>
-                                        <input className="presBox-input"
-                                            style={{ textAlign: 'left', width: 50 }}
-                                            type="number" value={NumCast(activeItem.presPinViewScale)}
-                                            onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { const val = e.target.value; activeItem.presPinViewScale = Number(val); })} />
-                                    </div>
-                                </div>
-                            </div> : (null)}
-                            {this.scrollable ? <div style={{ display: activeItem.presPinView ? "block" : "none" }}>
-                                <div className="ribbon-doubleButton" style={{ marginRight: 10 }}>
-                                    <div className="presBox-subheading">Scroll</div>
-                                    <div className="ribbon-property" style={{ paddingRight: 0, paddingLeft: 0 }}>
-                                        <input className="presBox-input"
-                                            style={{ textAlign: 'left', width: 50 }}
-                                            type="number" value={NumCast(activeItem.presPinViewScroll)}
-                                            onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { const val = e.target.value; activeItem.presPinViewScroll = Number(val); })} />
-                                    </div>
-                                </div>
-                            </div> : (null)}
-                            {/* <div className="ribbon-doubleButton" style={{ display: targetDoc.type === DocumentType.WEB ? "inline-flex" : "none" }}>
-                                <div className="ribbon-toggle" onClick={this.progressivizeText}>Store original website</div>
-                            </div> */}
-                        </div>
+                        </div> */}
                     </div>
                 </div >
             );
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 8ce76a347..998ca839d 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -21,6 +21,8 @@ import { documentSchema } from "../../../fields/documentSchemas";
 import { Networking } from "../../Network";
 import { SnappingManager } from "../../util/SnappingManager";
 import { SelectionManager } from "../../util/SelectionManager";
+import { LinkDocPreview } from "./LinkDocPreview";
+import { FormattedTextBoxComment } from "./formattedText/FormattedTextBoxComment";
 const path = require('path');
 
 export const timeSchema = createSchema({
@@ -32,8 +34,9 @@ const VideoDocument = makeInterface(documentSchema, timeSchema);
 @observer
 export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoDocument>(VideoDocument) {
     static _youtubeIframeCounter: number = 0;
-    private _reactionDisposer?: IReactionDisposer;
-    private _youtubeReactionDisposer?: IReactionDisposer;
+    // private _reactionDisposer?: IReactionDisposer;
+    // private _youtubeReactionDisposer?: IReactionDisposer;
+    private _disposers: { [name: string]: IReactionDisposer } = {};
     private _youtubePlayer: YT.Player | undefined = undefined;
     private _videoRef: HTMLVideoElement | null = null;
     private _youtubeIframeId: number = -1;
@@ -181,7 +184,32 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
 
     componentDidMount() {
         if (this.props.setVideoBox) this.props.setVideoBox(this);
-
+        this._disposers.videoStart = reaction(
+            () => this.Document._videoStart,
+            (videoStart) => {
+                if (videoStart !== undefined) {
+                    if (this.props.renderDepth !== -1 && !LinkDocPreview.TargetDoc && !FormattedTextBoxComment.linkDoc) {
+                        const delay = this.player ? 0 : 250; // wait for mainCont and try again to play
+                        setTimeout(() => this.player && this.Play(), delay);
+                        setTimeout(() => { this.Document._videoStart = undefined; }, 10 + delay);
+                    }
+                }
+            },
+            { fireImmediately: true }
+        );
+        this._disposers.videoStop = reaction(
+            () => this.Document._videoStop,
+            (videoStop) => {
+                if (videoStop !== undefined) {
+                    if (this.props.renderDepth !== -1 && !LinkDocPreview.TargetDoc && !FormattedTextBoxComment.linkDoc) {
+                        const delay = this.player ? 0 : 250; // wait for mainCont and try again to play
+                        setTimeout(() => this.player && this.Pause(), delay);
+                        setTimeout(() => { this.Document._videoStop = undefined; }, 10 + delay);
+                    }
+                }
+            },
+            { fireImmediately: true }
+        );
         if (this.youtubeVideoId) {
             const youtubeaspect = 400 / 315;
             const nativeWidth = Doc.NativeWidth(this.layoutDoc);
@@ -196,8 +224,9 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
 
     componentWillUnmount() {
         this.Pause();
-        this._reactionDisposer?.();
-        this._youtubeReactionDisposer?.();
+        this._disposers.reactionDisposer?.();
+        this._disposers.youtubeReactionDisposer?.();
+        this._disposers.videoStart?.();
     }
 
     @action
@@ -207,8 +236,8 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
             this._videoRef!.ontimeupdate = this.updateTimecode;
             // @ts-ignore
             vref.onfullscreenchange = action((e) => this._fullScreen = vref.webkitDisplayingFullscreen);
-            this._reactionDisposer?.();
-            this._reactionDisposer = reaction(() => (this.layoutDoc._currentTimecode || 0),
+            this._disposers.reactionDisposer?.();
+            this._disposers.reactionDisposer = reaction(() => (this.layoutDoc._currentTimecode || 0),
                 time => !this._playing && (vref.currentTime = time), { fireImmediately: true });
         }
     }
@@ -293,10 +322,10 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
             if (event.data === YT.PlayerState.PAUSED && this._playing) this.Pause(false);
         });
         const onYoutubePlayerReady = (event: any) => {
-            this._reactionDisposer?.();
-            this._youtubeReactionDisposer?.();
-            this._reactionDisposer = reaction(() => this.layoutDoc._currentTimecode, () => !this._playing && this.Seek((this.layoutDoc._currentTimecode || 0)));
-            this._youtubeReactionDisposer = reaction(
+            this._disposers.reactionDisposer?.();
+            this._disposers.youtubeReactionDisposer?.();
+            this._disposers.reactionDisposer = reaction(() => this.layoutDoc._currentTimecode, () => !this._playing && this.Seek((this.layoutDoc._currentTimecode || 0)));
+            this._disposers.youtubeReactionDisposer = reaction(
                 () => !this.props.Document.isAnnotating && Doc.GetSelectedTool() === InkTool.None && this.props.isSelected(true) && !SnappingManager.GetIsDragging() && !DocumentDecorations.Instance.Interacting,
                 (interactive) => iframe.style.pointerEvents = interactive ? "all" : "none", { fireImmediately: true });
         };
diff --git a/src/client/views/presentationview/PresElementBox.scss b/src/client/views/presentationview/PresElementBox.scss
index ed1aa9a1e..e1eeefc30 100644
--- a/src/client/views/presentationview/PresElementBox.scss
+++ b/src/client/views/presentationview/PresElementBox.scss
@@ -122,12 +122,6 @@ $slide-active: #5B9FDD;
     }
 
 
-    .presItem-slideButtons {
-        display: none;
-    }
-}
-
-.presItem-slide:hover {
     .presItem-slideButtons {
         display: flex;
         grid-column: 7;
@@ -162,6 +156,41 @@ $slide-active: #5B9FDD;
     }
 }
 
+// .presItem-slide:hover {
+    //     .presItem-slideButtons {
+    //         display: flex;
+    //         grid-column: 7;
+    //         grid-row: 1/3;
+    //         width: max-content;
+    //         justify-self: right;
+    //         justify-content: flex-end;
+
+    //         .slideButton {
+    //             cursor: pointer;
+    //             position: relative;
+    //             border-radius: 100px;
+    //             z-index: 300;
+    //             width: 18px;
+    //             height: 18px;
+    //             display: flex;
+    //             font-size: 12px;
+    //             justify-self: center;
+    //             align-self: center;
+    //             background-color: rgba(0, 0, 0, 0.5);
+    //             color: white;
+    //             justify-content: center;
+    //             align-items: center;
+    //             transition: 0.2s;
+    //             margin-right: 3px;
+    //         }
+
+    //         .slideButton:hover {
+    //             background-color: rgba(0, 0, 0, 1);
+    //             transform: scale(1.2);
+    //         }
+    //     }
+    // }
+
 .presItem-slide.active {
     box-shadow: 0 0 0px 1.5px $dark-blue;
 }
diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx
index 463249ab8..9ec39b792 100644
--- a/src/client/views/presentationview/PresElementBox.tsx
+++ b/src/client/views/presentationview/PresElementBox.tsx
@@ -348,6 +348,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
                             <div className="slideButton"
                                 onClick={() => activeItem.groupWithUp = !activeItem.groupWithUp}
                                 style={{
+                                    zIndex: 1000 - this.indexInPres,
                                     fontWeight: 700,
                                     backgroundColor: activeItem.groupWithUp ? presColorBool ? presBoxColor : PresColor.DarkBlue : undefined,
                                     height: activeItem.groupWithUp ? 53 : 18,
@@ -367,7 +368,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
                             <FontAwesomeIcon icon={"trash"} onPointerDown={e => e.stopPropagation()} />
                         </div></Tooltip>
                     </div>
-                    <div className="presItem-docName" style={{ maxWidth: showMore ? (toolbarWidth - 185) : toolbarWidth - 95 }}>{activeItem.presPinView ? (<><i>View of </i> {targetDoc.title}</>) : targetDoc.title}</div>
+                    <div className="presItem-docName" style={{ maxWidth: showMore ? (toolbarWidth - 195) : toolbarWidth - 105 }}>{activeItem.presPinView ? (<><i>View of </i> {targetDoc.title}</>) : targetDoc.title}</div>
                     {this.renderEmbeddedInline}
                 </div>}
             </div >);
diff --git a/src/client/views/presentationview/PresProperties.tsx b/src/client/views/presentationview/PresProperties.tsx
new file mode 100644
index 000000000..edad41861
--- /dev/null
+++ b/src/client/views/presentationview/PresProperties.tsx
@@ -0,0 +1,492 @@
+import React from "react";
+import { action, computed, observable, reaction } from "mobx";
+import { Doc } from "../../../fields/Doc";
+import { BoolCast, Cast, NumCast } from "../../../fields/Types";
+import { undoBatch, UndoManager } from "../../util/UndoManager";
+import { PresBox, PresColor, PresEffect, PresMovement } from "../nodes/PresBox";
+import { DocumentType } from "../../documents/DocumentTypes";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { CollectionViewType } from "../collections/CollectionView";
+import { Tooltip } from "@material-ui/core";
+
+
+export class PresProperties {
+
+    @observable public static Instance: PresProperties;
+
+    @computed get pres(): PresBox { return PresBox.Instance; }
+
+    @computed get activeItem() { return Cast(this.pres.childDocs[NumCast(PresBox.Instance.rootDoc._itemIndex)], Doc, null); }
+    @computed get targetDoc() { return Cast(this.pres.activeItem?.presentationTargetDoc, Doc, null); }
+
+    @computed get scrollable(): boolean {
+        if (this.targetDoc.type === DocumentType.PDF || this.targetDoc.type === DocumentType.WEB || this.targetDoc.type === DocumentType.RTF || this.targetDoc._viewType === CollectionViewType.Stacking) return true;
+        else return false;
+    }
+    @computed get panable(): boolean {
+        if ((this.targetDoc.type === DocumentType.COL && this.targetDoc._viewType === CollectionViewType.Freeform) || this.targetDoc.type === DocumentType.IMG) return true;
+        else return false;
+    }
+
+
+    @observable private openMovementDropdown: boolean = false;
+    @observable private openEffectDropdown: boolean = false;
+
+    _batch: UndoManager.Batch | undefined = undefined;
+
+
+    @computed get effectDirection(): string {
+        let effect = '';
+        switch (this.targetDoc.presEffectDirection) {
+            case 'left': effect = "Enter from left"; break;
+            case 'right': effect = "Enter from right"; break;
+            case 'top': effect = "Enter from top"; break;
+            case 'bottom': effect = "Enter from bottom"; break;
+            default: effect = "Enter from center"; break;
+        }
+        return effect;
+    }
+
+    @undoBatch
+    @action
+    updateHideBefore = (activeItem: Doc) => {
+        activeItem.presHideBefore = !activeItem.presHideBefore;
+        Array.from(this.pres._selectedArray.keys()).forEach((doc) => doc.presHideBefore = activeItem.presHideBefore);
+    }
+
+    @undoBatch
+    @action
+    updateHideAfter = (activeItem: Doc) => {
+        activeItem.presHideAfter = !activeItem.presHideAfter;
+        Array.from(this.pres._selectedArray.keys()).forEach((doc) => doc.presHideAfter = activeItem.presHideAfter);
+    }
+
+    @undoBatch
+    @action
+    updateOpenDoc = (activeItem: Doc) => {
+        activeItem.openDocument = !activeItem.openDocument;
+        Array.from(this.pres._selectedArray.keys()).forEach((doc) => {
+            doc.openDocument = activeItem.openDocument;
+        });
+    }
+
+    /**
+     * When the movement dropdown is changes
+     */
+    @undoBatch
+    updateMovement = action((movement: any, all?: boolean) => {
+        const array: any[] = all ? this.pres.childDocs : Array.from(this.pres._selectedArray.keys());
+        array.forEach((doc) => {
+            switch (movement) {
+                case PresMovement.Zoom: //Pan and zoom
+                    doc.presMovement = PresMovement.Zoom;
+                    break;
+                case PresMovement.Pan: //Pan
+                    doc.presMovement = PresMovement.Pan;
+                    break;
+                case PresMovement.Jump: //Jump Cut
+                    doc.presJump = true;
+                    doc.presMovement = PresMovement.Jump;
+                    break;
+                case PresMovement.None: default:
+                    doc.presMovement = PresMovement.None;
+                    break;
+            }
+        });
+    });
+
+    @undoBatch
+    @action
+    updateEffect = (effect: any, all?: boolean) => {
+        const array: any[] = all ? this.pres.childDocs : Array.from(this.pres._selectedArray.keys());
+        array.forEach((doc) => {
+            const tagDoc = Cast(doc.presentationTargetDoc, Doc, null);
+            switch (effect) {
+                case PresEffect.Bounce:
+                    tagDoc.presEffect = PresEffect.Bounce;
+                    break;
+                case PresEffect.Fade:
+                    tagDoc.presEffect = PresEffect.Fade;
+                    break;
+                case PresEffect.Flip:
+                    tagDoc.presEffect = PresEffect.Flip;
+                    break;
+                case PresEffect.Roll:
+                    tagDoc.presEffect = PresEffect.Roll;
+                    break;
+                case PresEffect.Rotate:
+                    tagDoc.presEffect = PresEffect.Rotate;
+                    break;
+                case PresEffect.None: default:
+                    tagDoc.presEffect = PresEffect.None;
+                    break;
+            }
+        });
+    }
+
+    @undoBatch
+    @action
+    updateEffectDirection = (effect: any, all?: boolean) => {
+        const array: any[] = all ? this.pres.childDocs : Array.from(this.pres._selectedArray.keys());
+        array.forEach((doc) => {
+            const tagDoc = Cast(doc.presentationTargetDoc, Doc, null);
+            switch (effect) {
+                case PresEffect.Left:
+                    tagDoc.presEffectDirection = PresEffect.Left;
+                    break;
+                case PresEffect.Right:
+                    tagDoc.presEffectDirection = PresEffect.Right;
+                    break;
+                case PresEffect.Top:
+                    tagDoc.presEffectDirection = PresEffect.Top;
+                    break;
+                case PresEffect.Bottom:
+                    tagDoc.presEffectDirection = PresEffect.Bottom;
+                    break;
+                case PresEffect.Center: default:
+                    tagDoc.presEffectDirection = PresEffect.Center;
+                    break;
+            }
+        });
+    }
+
+    // Converts seconds to ms and updates presTransition
+    setTransitionTime = (number: String, change?: number) => {
+        let timeInMS = Number(number) * 1000;
+        if (change) timeInMS += change;
+        if (timeInMS < 100) timeInMS = 100;
+        if (timeInMS > 10000) timeInMS = 10000;
+        Array.from(PresBox.Instance._selectedArray.keys()).forEach((doc) => doc.presTransition = timeInMS);
+    }
+
+    // Converts seconds to ms and updates presDuration
+    setDurationTime = (number: String, change?: number) => {
+        let timeInMS = Number(number) * 1000;
+        if (change) timeInMS += change;
+        if (timeInMS < 100) timeInMS = 100;
+        if (timeInMS > 20000) timeInMS = 20000;
+        Array.from(PresBox.Instance._selectedArray.keys()).forEach((doc) => doc.presDuration = timeInMS);
+    }
+
+    setMovementName = action((movement: any, activeItem: Doc): string => {
+        let output: string = 'none';
+        switch (movement) {
+            case PresMovement.Zoom: output = 'Pan & Zoom'; break; //Pan and zoom
+            case PresMovement.Pan: output = 'Pan'; break; //Pan
+            case PresMovement.Jump: output = 'Jump cut'; break; //Jump Cut
+            case PresMovement.None: output = 'No Movement'; break; //None
+            default: output = 'Zoom'; activeItem.presMovement = 'zoom'; break; //default set as zoom
+        }
+        return output;
+    });
+
+    @computed get transitionDropdown() {
+        const activeItem: Doc = this.activeItem;
+        const targetDoc: Doc = this.targetDoc;
+        const isPresCollection: boolean = (targetDoc === this.pres.layoutDoc.presCollection);
+        const isPinWithView: boolean = BoolCast(activeItem.presPinView);
+        if (activeItem && targetDoc) {
+            const transitionSpeed = activeItem.presTransition ? NumCast(activeItem.presTransition) / 1000 : 0.5;
+            let duration = activeItem.presDuration ? NumCast(activeItem.presDuration) / 1000 : 2;
+            if (activeItem.type === DocumentType.AUDIO) duration = NumCast(activeItem.duration);
+            const effect = targetDoc.presEffect ? targetDoc.presEffect : 'None';
+            activeItem.presMovement = activeItem.presMovement ? activeItem.presMovement : 'Zoom';
+            return (
+                <div className={`presBox-ribbon ${this.pres.layoutDoc.presStatus === "edit" ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onClick={action(e => { e.stopPropagation(); this.openMovementDropdown = false; this.openEffectDropdown = false; })}>
+                    <div className="ribbon-box">
+                        Movement
+                        {isPresCollection || (isPresCollection && isPinWithView) ?
+                            <div className="ribbon-property" style={{ marginLeft: 0, height: 25, textAlign: 'left', paddingLeft: 5, paddingRight: 5, fontSize: 10 }}>
+                                {this.scrollable ? "Scroll to pinned view" : !isPinWithView ? "No movement" : "Pan & Zoom to pinned view"}
+                            </div>
+                            :
+                            <div className="presBox-dropdown" onClick={action(e => { e.stopPropagation(); this.openMovementDropdown = !this.openMovementDropdown; })} style={{ borderBottomLeftRadius: this.openMovementDropdown ? 0 : 5, border: this.openMovementDropdown ? `solid 2px ${PresColor.DarkBlue}` : 'solid 1px black' }}>
+                                {this.setMovementName(activeItem.presMovement, activeItem)}
+                                <FontAwesomeIcon className='presBox-dropdownIcon' style={{ gridColumn: 2, color: this.openMovementDropdown ? PresColor.DarkBlue : 'black' }} icon={"angle-down"} />
+                                <div className={'presBox-dropdownOptions'} id={'presBoxMovementDropdown'} onPointerDown={e => e.stopPropagation()} style={{ display: this.openMovementDropdown ? "grid" : "none" }}>
+                                    <div className={`presBox-dropdownOption ${activeItem.presMovement === PresMovement.None ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.None)}>None</div>
+                                    <div className={`presBox-dropdownOption ${activeItem.presMovement === PresMovement.Zoom ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.Zoom)}>Pan {"&"} Zoom</div>
+                                    <div className={`presBox-dropdownOption ${activeItem.presMovement === PresMovement.Pan ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.Pan)}>Pan</div>
+                                    <div className={`presBox-dropdownOption ${activeItem.presMovement === PresMovement.Jump ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.Jump)}>Jump cut</div>
+                                </div>
+                            </div>
+                        }
+                        <div className="ribbon-doubleButton" style={{ display: activeItem.presMovement === PresMovement.Pan || activeItem.presMovement === PresMovement.Zoom ? "inline-flex" : "none" }}>
+                            <div className="presBox-subheading">Transition Speed</div>
+                            <div className="ribbon-property">
+                                <input className="presBox-input"
+                                    type="number" value={transitionSpeed}
+                                    onChange={action((e) => this.setTransitionTime(e.target.value))} /> s
+                            </div>
+                            <div className="ribbon-propertyUpDown">
+                                <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setTransitionTime(String(transitionSpeed), 1000))}>
+                                    <FontAwesomeIcon icon={"caret-up"} />
+                                </div>
+                                <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setTransitionTime(String(transitionSpeed), -1000))}>
+                                    <FontAwesomeIcon icon={"caret-down"} />
+                                </div>
+                            </div>
+                        </div>
+                        <input type="range" step="0.1" min="0.1" max="10" value={transitionSpeed}
+                            className={`toolbar-slider ${activeItem.presMovement === PresMovement.Pan || activeItem.presMovement === PresMovement.Zoom ? "" : "none"}`}
+                            id="toolbar-slider"
+                            onPointerDown={() => this._batch = UndoManager.StartBatch("presTransition")}
+                            onPointerUp={() => this._batch?.end()}
+                            onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
+                                e.stopPropagation();
+                                this.setTransitionTime(e.target.value);
+                            }} />
+                        <div className={`slider-headers ${activeItem.presMovement === PresMovement.Pan || activeItem.presMovement === PresMovement.Zoom ? "" : "none"}`}>
+                            <div className="slider-text">Fast</div>
+                            <div className="slider-text">Medium</div>
+                            <div className="slider-text">Slow</div>
+                        </div>
+                    </div>
+                    <div className="ribbon-box">
+                        Visibility {"&"} Duration
+                        <div className="ribbon-doubleButton">
+                            {isPresCollection ? (null) : <Tooltip title={<><div className="dash-tooltip">{"Hide before presented"}</div></>}><div className={`ribbon-toggle ${activeItem.presHideBefore ? "active" : ""}`} onClick={() => this.updateHideBefore(activeItem)}>Hide before</div></Tooltip>}
+                            {isPresCollection ? (null) : <Tooltip title={<><div className="dash-tooltip">{"Hide after presented"}</div></>}><div className={`ribbon-toggle ${activeItem.presHideAfter ? "active" : ""}`} onClick={() => this.updateHideAfter(activeItem)}>Hide after</div></Tooltip>}
+                            <Tooltip title={<><div className="dash-tooltip">{"Open document in a new tab"}</div></>}><div className="ribbon-toggle" style={{ backgroundColor: activeItem.openDocument ? PresColor.LightBlue : "" }} onClick={() => this.updateOpenDoc(activeItem)}>Open</div></Tooltip>
+                        </div>
+                        <div className="ribbon-doubleButton" >
+                            <div className="presBox-subheading">Slide Duration</div>
+                            <div className="ribbon-property">
+                                <input className="presBox-input"
+                                    type="number" value={duration}
+                                    onChange={action((e) => this.setDurationTime(e.target.value))} /> s
+                            </div>
+                            <div className="ribbon-propertyUpDown">
+                                <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setDurationTime(String(duration), 1000))}>
+                                    <FontAwesomeIcon icon={"caret-up"} />
+                                </div>
+                                <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setDurationTime(String(duration), -1000))}>
+                                    <FontAwesomeIcon icon={"caret-down"} />
+                                </div>
+                            </div>
+                        </div>
+                        <input type="range" step="0.1" min="0.1" max="20" value={duration}
+                            style={{ display: targetDoc.type === DocumentType.AUDIO ? "none" : "block" }}
+                            className={"toolbar-slider"} id="duration-slider"
+                            onPointerDown={() => { this._batch = UndoManager.StartBatch("presDuration"); }}
+                            onPointerUp={() => { if (this._batch) this._batch.end(); }}
+                            onChange={(e: React.ChangeEvent<HTMLInputElement>) => { e.stopPropagation(); this.setDurationTime(e.target.value); }}
+                        />
+                        <div className={"slider-headers"} style={{ display: targetDoc.type === DocumentType.AUDIO ? "none" : "grid" }}>
+                            <div className="slider-text">Short</div>
+                            <div className="slider-text">Medium</div>
+                            <div className="slider-text">Long</div>
+                        </div>
+                    </div>
+                    {isPresCollection ? (null) : <div className="ribbon-box">
+                        Effects
+                        <div className="presBox-dropdown" onClick={action(e => { e.stopPropagation(); this.openEffectDropdown = !this.openEffectDropdown; })} style={{ borderBottomLeftRadius: this.openEffectDropdown ? 0 : 5, border: this.openEffectDropdown ? `solid 2px ${PresColor.DarkBlue}` : 'solid 1px black' }}>
+                            {effect}
+                            <FontAwesomeIcon className='presBox-dropdownIcon' style={{ gridColumn: 2, color: this.openEffectDropdown ? PresColor.DarkBlue : 'black' }} icon={"angle-down"} />
+                            <div className={'presBox-dropdownOptions'} id={'presBoxMovementDropdown'} style={{ display: this.openEffectDropdown ? "grid" : "none" }} onPointerDown={e => e.stopPropagation()}>
+                                <div className={`presBox-dropdownOption ${targetDoc.presEffect === PresEffect.None || !targetDoc.presEffect ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.None)}>None</div>
+                                <div className={`presBox-dropdownOption ${targetDoc.presEffect === PresEffect.Fade ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Fade)}>Fade In</div>
+                                <div className={`presBox-dropdownOption ${targetDoc.presEffect === PresEffect.Flip ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Flip)}>Flip</div>
+                                <div className={`presBox-dropdownOption ${targetDoc.presEffect === PresEffect.Rotate ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Rotate)}>Rotate</div>
+                                <div className={`presBox-dropdownOption ${targetDoc.presEffect === PresEffect.Bounce ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Bounce)}>Bounce</div>
+                                <div className={`presBox-dropdownOption ${targetDoc.presEffect === PresEffect.Roll ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Roll)}>Roll</div>
+                            </div>
+                        </div>
+                        <div className="ribbon-doubleButton" style={{ display: effect === 'None' ? "none" : "inline-flex" }}>
+                            <div className="presBox-subheading" >Effect direction</div>
+                            <div className="ribbon-property">
+                                {this.effectDirection}
+                            </div>
+                        </div>
+                        <div className="effectDirection" style={{ display: effect === 'None' ? "none" : "grid", width: 40 }}>
+                            <Tooltip title={<><div className="dash-tooltip">{"Enter from left"}</div></>}><div style={{ gridColumn: 1, gridRow: 2, justifySelf: 'center', color: targetDoc.presEffectDirection === PresEffect.Left ? PresColor.LightBlue : "black", cursor: "pointer" }} onClick={() => this.updateEffectDirection(PresEffect.Left)}><FontAwesomeIcon icon={"angle-right"} /></div></Tooltip>
+                            <Tooltip title={<><div className="dash-tooltip">{"Enter from right"}</div></>}><div style={{ gridColumn: 3, gridRow: 2, justifySelf: 'center', color: targetDoc.presEffectDirection === PresEffect.Right ? PresColor.LightBlue : "black", cursor: "pointer" }} onClick={() => this.updateEffectDirection(PresEffect.Right)}><FontAwesomeIcon icon={"angle-left"} /></div></Tooltip>
+                            <Tooltip title={<><div className="dash-tooltip">{"Enter from top"}</div></>}><div style={{ gridColumn: 2, gridRow: 1, justifySelf: 'center', color: targetDoc.presEffectDirection === PresEffect.Top ? PresColor.LightBlue : "black", cursor: "pointer" }} onClick={() => this.updateEffectDirection(PresEffect.Top)}><FontAwesomeIcon icon={"angle-down"} /></div></Tooltip>
+                            <Tooltip title={<><div className="dash-tooltip">{"Enter from bottom"}</div></>}><div style={{ gridColumn: 2, gridRow: 3, justifySelf: 'center', color: targetDoc.presEffectDirection === PresEffect.Bottom ? PresColor.LightBlue : "black", cursor: "pointer" }} onClick={() => this.updateEffectDirection(PresEffect.Bottom)}><FontAwesomeIcon icon={"angle-up"} /></div></Tooltip>
+                            <Tooltip title={<><div className="dash-tooltip">{"Enter from center"}</div></>}><div style={{ gridColumn: 2, gridRow: 2, width: 10, height: 10, alignSelf: 'center', justifySelf: 'center', border: targetDoc.presEffectDirection === PresEffect.Center || !targetDoc.presEffectDirection ? `solid 2px ${PresColor.LightBlue}` : "solid 2px black", borderRadius: "100%", cursor: "pointer" }} onClick={() => this.updateEffectDirection(PresEffect.Center)}></div></Tooltip>
+                        </div>
+                    </div>}
+                    <div className="ribbon-final-box">
+                        <div className="ribbon-final-button-hidden" onClick={() => this.applyTo(this.pres.childDocs)}>
+                            Apply to all
+                        </div>
+                    </div>
+                </div >
+            );
+        }
+    }
+
+    @undoBatch
+    @action
+    applyTo = (array: Doc[]) => {
+        const activeItem: Doc = this.activeItem;
+        const targetDoc: Doc = this.targetDoc;
+        this.updateMovement(activeItem.presMovement, true);
+        this.updateEffect(targetDoc.presEffect, true);
+        this.updateEffectDirection(targetDoc.presEffectDirection, true);
+        array.forEach((doc) => {
+            const curDoc = Cast(doc, Doc, null);
+            const tagDoc = Cast(curDoc.presentationTargetDoc, Doc, null);
+            if (tagDoc && targetDoc) {
+                curDoc.presTransition = activeItem.presTransition;
+                curDoc.presDuration = activeItem.presDuration;
+                curDoc.presHideBefore = activeItem.presHideBefore;
+                curDoc.presHideAfter = activeItem.presHideAfter;
+            }
+        });
+    }
+
+    @computed get mediaOptionsDropdown() {
+        const activeItem: Doc = this.activeItem;
+        const targetDoc: Doc = this.targetDoc;
+        if (activeItem && targetDoc) {
+            return (
+                <div>
+                    <div className={'presBox-ribbon'} onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
+                        <div className="ribbon-box">
+                            <div className="ribbon-doubleButton" style={{ display: targetDoc.type === DocumentType.AUDIO ? "inline-flex" : "none" }}>
+                                <div className="ribbon-toggle" style={{ backgroundColor: activeItem.playAuto ? PresColor.LightBlue : "" }} onClick={() => activeItem.playAuto = !activeItem.playAuto}>Play automatically</div>
+                                <div className="ribbon-toggle" style={{ display: "flex", backgroundColor: activeItem.playAuto ? "" : PresColor.LightBlue }} onClick={() => activeItem.playAuto = !activeItem.playAuto}>Play on next</div>
+                            </div>
+                            {/* {targetDoc.type === DocumentType.VID ? <div className="ribbon-toggle" style={{ backgroundColor: activeItem.presVidFullScreen ? PresColor.LightBlue : "" }} onClick={() => activeItem.presVidFullScreen = !activeItem.presVidFullScreen}>Full screen</div> : (null)} */}
+                            {targetDoc.type === DocumentType.AUDIO ? <div className="ribbon-doubleButton" style={{ marginRight: 10 }}>
+                                <div className="presBox-subheading">Start time</div>
+                                <div className="ribbon-property" style={{ paddingRight: 0, paddingLeft: 0 }}>
+                                    <input className="presBox-input"
+                                        style={{ textAlign: 'left', width: 50 }}
+                                        type="number" value={NumCast(activeItem.presStartTime)}
+                                        onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { activeItem.presStartTime = Number(e.target.value); })} />
+                                </div>
+                            </div> : (null)}
+                            {targetDoc.type === DocumentType.AUDIO ? <div className="ribbon-doubleButton" style={{ marginRight: 10 }}>
+                                <div className="presBox-subheading">End time</div>
+                                <div className="ribbon-property" style={{ paddingRight: 0, paddingLeft: 0 }}>
+                                    <input className="presBox-input"
+                                        style={{ textAlign: 'left', width: 50 }}
+                                        type="number" value={NumCast(activeItem.presEndTime)}
+                                        onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { const val = e.target.value; activeItem.presEndTime = Number(val); })} />
+                                </div>
+                            </div> : (null)}
+                        </div>
+                    </div>
+                </div >
+            );
+        }
+    }
+
+    @computed get presPinViewOptionsDropdown() {
+        const activeItem: Doc = this.activeItem;
+        const targetDoc: Doc = this.targetDoc;
+        const presPinWithViewIcon = <img src="/assets/pinWithView.png" style={{ margin: "auto", width: 16, filter: 'invert(1)' }} />;
+        return (
+            <>
+                {this.panable || this.scrollable || this.targetDoc.type === DocumentType.COMPARISON ? 'Pinned view' : (null)}
+                <div className="ribbon-doubleButton">
+                    <Tooltip title={<><div className="dash-tooltip">{activeItem.presPinView ? "Turn off pin with view" : "Turn on pin with view"}</div></>}><div className="ribbon-toggle" style={{ width: 20, padding: 0, backgroundColor: activeItem.presPinView ? PresColor.LightBlue : "" }}
+                        onClick={() => {
+                            activeItem.presPinView = !activeItem.presPinView;
+                            targetDoc.presPinView = activeItem.presPinView;
+                            if (activeItem.presPinView) {
+                                if (targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.RTF || targetDoc.type === DocumentType.WEB || targetDoc._viewType === CollectionViewType.Stacking) {
+                                    const scroll = targetDoc._scrollTop;
+                                    activeItem.presPinView = true;
+                                    activeItem.presPinViewScroll = scroll;
+                                } else if (targetDoc.type === DocumentType.VID) {
+                                    activeItem.presPinTimecode = targetDoc._currentTimecode;
+                                } else if ((targetDoc.type === DocumentType.COL && targetDoc._viewType === CollectionViewType.Freeform) || targetDoc.type === DocumentType.IMG) {
+                                    const x = targetDoc._panX;
+                                    const y = targetDoc._panY;
+                                    const scale = targetDoc._viewScale;
+                                    activeItem.presPinView = true;
+                                    activeItem.presPinViewX = x;
+                                    activeItem.presPinViewY = y;
+                                    activeItem.presPinViewScale = scale;
+                                } else if (targetDoc.type === DocumentType.COMPARISON) {
+                                    const width = targetDoc._clipWidth;
+                                    activeItem.presPinClipWidth = width;
+                                    activeItem.presPinView = true;
+                                }
+                            }
+                        }}>{presPinWithViewIcon}</div></Tooltip>
+                    {activeItem.presPinView ? <Tooltip title={<><div className="dash-tooltip">{"Update the pinned view with the view of the selected document"}</div></>}><div className="ribbon-button"
+                        onClick={() => {
+                            if (targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.WEB || targetDoc.type === DocumentType.RTF) {
+                                const scroll = targetDoc._scrollTop;
+                                activeItem.presPinViewScroll = scroll;
+                            } else if (targetDoc.type === DocumentType.VID) {
+                                activeItem.presPinTimecode = targetDoc._currentTimecode;
+                            } else if (targetDoc.type === DocumentType.COMPARISON) {
+                                const clipWidth = targetDoc._clipWidth;
+                                activeItem.presPinClipWidth = clipWidth;
+                            } else {
+                                const x = targetDoc._panX;
+                                const y = targetDoc._panY;
+                                const scale = targetDoc._viewScale;
+                                activeItem.presPinViewX = x;
+                                activeItem.presPinViewY = y;
+                                activeItem.presPinViewScale = scale;
+                            }
+                        }}>Update</div></Tooltip> : (null)}
+                </div>
+            </>
+        );
+    }
+
+    @computed get panOptionsDropdown() {
+        const activeItem: Doc = this.activeItem;
+        const targetDoc: Doc = this.targetDoc;
+        return (
+            <>
+                {this.panable ? <div style={{ display: activeItem.presPinView ? "block" : "none" }}>
+                    <div className="ribbon-doubleButton" style={{ marginRight: 10 }}>
+                        <div className="presBox-subheading">Pan X</div>
+                        <div className="ribbon-property" style={{ paddingRight: 0, paddingLeft: 0 }}>
+                            <input className="presBox-input"
+                                style={{ textAlign: 'left', width: 50 }}
+                                type="number" value={NumCast(activeItem.presPinViewX)}
+                                onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { const val = e.target.value; activeItem.presPinViewX = Number(val); })} />
+                        </div>
+                    </div>
+                    <div className="ribbon-doubleButton" style={{ marginRight: 10 }}>
+                        <div className="presBox-subheading">Pan Y</div>
+                        <div className="ribbon-property" style={{ paddingRight: 0, paddingLeft: 0 }}>
+                            <input className="presBox-input"
+                                style={{ textAlign: 'left', width: 50 }}
+                                type="number" value={NumCast(activeItem.presPinViewY)}
+                                onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { const val = e.target.value; activeItem.presPinViewY = Number(val); })} />
+                        </div>
+                    </div>
+                    <div className="ribbon-doubleButton" style={{ marginRight: 10 }}>
+                        <div className="presBox-subheading">Scale</div>
+                        <div className="ribbon-property" style={{ paddingRight: 0, paddingLeft: 0 }}>
+                            <input className="presBox-input"
+                                style={{ textAlign: 'left', width: 50 }}
+                                type="number" value={NumCast(activeItem.presPinViewScale)}
+                                onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { const val = e.target.value; activeItem.presPinViewScale = Number(val); })} />
+                        </div>
+                    </div>
+                </div> : (null)}
+            </>
+        );
+    }
+
+    @computed get scrollOptionsDropdown() {
+        const activeItem: Doc = this.activeItem;
+        const targetDoc: Doc = this.targetDoc;
+        return (
+            <>
+                {this.scrollable ? <div style={{ display: activeItem.presPinView ? "block" : "none" }}>
+                    <div className="ribbon-doubleButton" style={{ marginRight: 10 }}>
+                        <div className="presBox-subheading">Scroll</div>
+                        <div className="ribbon-property" style={{ paddingRight: 0, paddingLeft: 0 }}>
+                            <input className="presBox-input"
+                                style={{ textAlign: 'left', width: 50 }}
+                                type="number" value={NumCast(activeItem.presPinViewScroll)}
+                                onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { const val = e.target.value; activeItem.presPinViewScroll = Number(val); })} />
+                        </div>
+                    </div>
+                </div> : (null)}
+            </>
+        );
+    }
+}
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From 4a7033ba4630c79981a2649469932b4a432f18e8 Mon Sep 17 00:00:00 2001
From: geireann <60007097+geireann@users.noreply.github.com>
Date: Mon, 30 Nov 2020 11:10:23 +0800
Subject: Audio updates

---
 src/client/views/PropertiesView.tsx                |  4 +-
 src/client/views/collections/TabDocView.tsx        |  2 +-
 src/client/views/nodes/PresBox.tsx                 | 83 ++++++++++------------
 .../views/presentationview/PresElementBox.tsx      |  2 +-
 4 files changed, 42 insertions(+), 49 deletions(-)

(limited to 'src/client/views/PropertiesView.tsx')

diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index c656a020e..bdba625f8 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -1016,7 +1016,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                             {PresBox.Instance.transitionDropdown}
                         </div> : null}
                     </div>}
-                    {/* {!selectedItem || type === DocumentType.VID || type === DocumentType.AUDIO ? (null) : <div className="propertiesView-presTrails">
+                    {!selectedItem || type === DocumentType.VID || type === DocumentType.AUDIO ? (null) : <div className="propertiesView-presTrails">
                         <div className="propertiesView-presTrails-title"
                             onPointerDown={action(() => this.openPresProgressivize = !this.openPresProgressivize)}
                             style={{ backgroundColor: this.openPresProgressivize ? "black" : "" }}>
@@ -1028,7 +1028,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                         {this.openPresProgressivize ? <div className="propertiesView-presTrails-content">
                             {PresBox.Instance.progressivizeDropdown}
                         </div> : null}
-                    </div>} */}
+                    </div>}
                     {!selectedItem || (type !== DocumentType.VID && type !== DocumentType.AUDIO) ? (null) : <div className="propertiesView-presTrails">
                         <div className="propertiesView-presTrails-title"
                             onPointerDown={action(() => { this.openSlideOptions = !this.openSlideOptions; })}
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 0f228bc06..258cdc4f7 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -172,7 +172,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
             const size: number = PresBox.Instance?._selectedArray.size;
             const presSelected: Doc | undefined = presArray && size ? presArray[size - 1] : undefined;
             Doc.AddDocToList(curPres, "data", pinDoc, presSelected);
-            if (pinDoc.type === DocumentType.AUDIO || pinDoc.type === DocumentType.VID && !audioRange) {
+            if (!audioRange && (pinDoc.type === DocumentType.AUDIO || pinDoc.type === DocumentType.VID)) {
                 pinDoc.mediaStart = "manual";
                 pinDoc.mediaStop = "manual";
                 pinDoc.presStartTime = 0;
diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx
index ed2cb9fa1..54818f67e 100644
--- a/src/client/views/nodes/PresBox.tsx
+++ b/src/client/views/nodes/PresBox.tsx
@@ -191,18 +191,20 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
     // 'Play on next' for audio or video therefore first navigate to the audio/video before it should be played
     nextAudioVideo = (targetDoc: Doc, activeItem: Doc) => {
         if (targetDoc.type === DocumentType.AUDIO) {
+            console.log("play audio");
             targetDoc._audioStart = NumCast(activeItem.presStartTime);
-
         } else if (targetDoc.type === DocumentType.VID) {
-            targetDoc._currentTimecode = NumCast(activeItem.presStartTime);
-            setTimeout(() => targetDoc._videoStart = true, 0);
+            console.log("play video");
+            targetDoc._videoStop = true;
+            setTimeout(() => targetDoc._currentTimecode = NumCast(activeItem.presStartTime), 10);
+            setTimeout(() => targetDoc._videoStart = true, 20);
         }
-        // if (targetDoc.type === DocumentType.VID) { VideoBox.Instance.Play() };
         activeItem.playNow = false;
     }
 
     // No more frames in current doc and next slide is defined, therefore move to next slide 
     nextSlide = (targetDoc: Doc, activeNext: Doc) => {
+        const targetNext = Cast(activeNext.presentationTargetDoc, Doc, null);
         let nextSelected = this.itemIndex + 1;
         this.gotoDocument(nextSelected);
         for (nextSelected = nextSelected + 1; nextSelected < this.childDocs.length; nextSelected++) {
@@ -213,11 +215,12 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                 this.gotoDocument(nextSelected, true);
             }
         }
-        const targetNext = Cast(activeNext.presentationTargetDoc, Doc, null);
         // If next slide is audio / video 'Play automatically' then the next slide should be played
-        if (activeNext && (targetNext.type === DocumentType.AUDIO || targetNext.type === DocumentType.VID) && activeNext.playAuto) {
-            if (targetNext.type === DocumentType.AUDIO) targetNext._audioStart = NumCast(activeNext.presStartTime);
-        } else if (targetNext.type === DocumentType.AUDIO || targetNext.type === DocumentType.VID) { activeNext.playNow = true; console.log('play next after it is navigated to'); }
+        if ((targetDoc.type === DocumentType.AUDIO || targetDoc.type === DocumentType.VID) && (activeNext.mediaStart === "auto" || activeNext.playNow)) {
+            this.nextAudioVideo(targetNext, activeNext);
+        } else if ((targetDoc.type === DocumentType.AUDIO || targetDoc.type === DocumentType.VID) && !activeNext.playNow && activeNext.mediaStart === "onClick") {
+            activeNext.playNow = true;
+        }
     }
 
     // Called when the user activates 'next' - to move to the next part of the pres. trail
@@ -234,14 +237,11 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
             // Case 1: There are still other frames and should go through all frames before going to next slide
             this.nextInternalFrame(targetDoc, activeItem);
         } else if (this.childDocs[this.itemIndex + 1] !== undefined) {
-            // Case 3: No more frames in current doc and next slide is defined, therefore move to next slide 
+            // Case 2: No more frames in current doc and next slide is defined, therefore move to next slide 
             this.nextSlide(targetDoc, activeNext);
-        } else if (this.childDocs[this.itemIndex + 1] === undefined && this.layoutDoc.presLoop) {
-            // Case 4: Last slide and presLoop is toggled ON
+        } else if (this.childDocs[this.itemIndex + 1] === undefined && (this.layoutDoc.presLoop || this.layoutDoc.presStatus === PresStatus.Edit)) {
+            // Case 3: Last slide and presLoop is toggled ON or it is in Edit mode
             this.gotoDocument(0);
-        } else if ((targetDoc.type === DocumentType.AUDIO || targetDoc.type === DocumentType.VID) && !activeItem.playAuto && activeItem.playNow && this.layoutDoc.presStatus !== PresStatus.Autoplay) {
-            // Case 2: 'Play on next' for audio or video therefore first navigate to the audio/video before it should be played
-            this.nextAudioVideo(targetDoc, activeItem);
         }
     }
 
@@ -517,10 +517,9 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
             try {
                 doc.opacity = 1;
             } catch (e) {
-                console.log("REset presentation error: ", e);
+                console.log("Reset presentation error: ", e);
             }
         });
-        ///for (const doc of this.childDocs) Cast(doc.presentationTargetDoc, Doc, null).opacity = 1;
     }
 
     @action togglePath = (srcContext: Doc, off?: boolean) => {
@@ -628,6 +627,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
             if (doc.type === DocumentType.LABEL) {
                 const audio = Cast(doc.annotationOn, Doc, null);
                 if (audio) {
+                    audio.mediaStart = "manual";
+                    audio.mediaStop = "manual";
                     audio.presStartTime = NumCast(doc.audioStart);
                     audio.presEndTime = NumCast(doc.audioEnd);
                     audio.presDuration = NumCast(doc.audioEnd) - NumCast(doc.audioStart);
@@ -1365,6 +1366,18 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                 <div>
                     <div className={'presBox-ribbon'} onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
                         <div>
+                            <div className="presBox-subheading">Range:</div>
+                            <div className={`slider-headers ${activeItem.presMovement === PresMovement.Pan || activeItem.presMovement === PresMovement.Zoom ? "" : "none"}`}>
+                                <div className="slider-text">
+                                    Start time:
+                                </div>
+                                <div className="slider-text">
+                                    Duration:
+                                </div>
+                                <div className="slider-text">
+                                    End time:
+                                </div>
+                            </div>
                             <div className="presBox-subheading">Start playing:</div>
                             <div className="presBox-radioButtons">
                                 <div className="checkbox-container">
@@ -1373,7 +1386,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                                         onChange={() => activeItem.mediaStart = "manual"}
                                         checked={activeItem.mediaStart === "manual"}
                                     />
-                                    <div>Start manually</div>
+                                    <div>Play manually</div>
                                 </div>
                                 <div className="checkbox-container">
                                     <input className="presBox-checkbox"
@@ -1381,15 +1394,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                                         onChange={() => activeItem.mediaStart = "auto"}
                                         checked={activeItem.mediaStart === "auto"}
                                     />
-                                    <div>Play with slide</div>
-                                </div>
-                                <div className="checkbox-container">
-                                    <input className="presBox-checkbox"
-                                        type="checkbox"
-                                        onChange={() => activeItem.mediaStart = "onClick"}
-                                        checked={activeItem.mediaStart === "onClick"}
-                                    />
-                                    <div>Play on click</div>
+                                    <div>Play automatically (with slide)</div>
                                 </div>
                             </div>
                             <div className="presBox-subheading">Stop playing:</div>
@@ -1400,7 +1405,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                                         onChange={() => activeItem.mediaStop = "manual"}
                                         checked={activeItem.mediaStop === "manual"}
                                     />
-                                    <div>Stop manually</div>
+                                    <div>Stop at end time</div>
                                 </div>
                                 <div className="checkbox-container">
                                     <input className="presBox-checkbox"
@@ -1408,7 +1413,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                                         onChange={() => activeItem.mediaStop = "afterCurrent"}
                                         checked={activeItem.mediaStop === "afterCurrent"}
                                     />
-                                    <div>After current slide</div>
+                                    <div>Stop automatically (current slide)</div>
                                 </div>
                                 <div className="checkbox-container">
                                     <input className="presBox-checkbox"
@@ -1416,7 +1421,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                                         onChange={() => activeItem.mediaStop = "afterSlide"}
                                         checked={activeItem.mediaStop === "afterSlide"}
                                     />
-                                    <div>After slide
+                                    <div>Stop after slide
                                     {activeItem.mediaStop !== "afterSlide" ?
                                             (null)
                                             :
@@ -1433,18 +1438,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                                     </div>
                                 </div>
                             </div>
-                            <div className="presBox-subheading">Range:</div>
-                            <div className={`slider-headers ${activeItem.presMovement === PresMovement.Pan || activeItem.presMovement === PresMovement.Zoom ? "" : "none"}`}>
-                                <div className="slider-text">
-                                    Start time:
-                                </div>
-                                <div className="slider-text">
-                                    Duration:
-                                </div>
-                                <div className="slider-text">
-                                    End time:
-                                </div>
-                            </div>
                             <div className={`slider-headers ${activeItem.presMovement === PresMovement.Pan || activeItem.presMovement === PresMovement.Zoom ? "" : "none"}`}>
                                 <div className="slider-text">
                                     <div className="ribbon-property" style={{ paddingRight: 0, paddingLeft: 0 }}>
@@ -1673,10 +1666,10 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         return (
             <div className={`dropdown-play ${this.presentTools ? "active" : ""}`} onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
                 <div className="dropdown-play-button" onClick={undoBatch(action(() => { this.updateMinimize(); this.turnOffEdit(true); }))}>
-                    Minimize
+                    Mini-player
                 </div>
                 <div className="dropdown-play-button" onClick={undoBatch(action(() => { this.layoutDoc.presStatus = "manual"; this.turnOffEdit(true); }))}>
-                    Sidebar view
+                    Sidebar player
                 </div>
             </div>
         );
@@ -1746,7 +1739,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
             return (
                 <div>
                     <div className={`presBox-ribbon ${this.progressivizeTools && this.layoutDoc.presStatus === "edit" ? "active" : ""}`} onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
-                        {/* <div className="ribbon-box">
+                        <div className="ribbon-box">
                             {this.stringType} selected
                             <div className="ribbon-doubleButton" style={{ borderTop: 'solid 1px darkgrey', display: (targetDoc.type === DocumentType.COL && targetDoc._viewType === 'freeform') || targetDoc.type === DocumentType.IMG || targetDoc.type === DocumentType.RTF ? "inline-flex" : "none" }}>
                                 <div className="ribbon-toggle" style={{ backgroundColor: activeItem.presProgressivize ? PresColor.LightBlue : "" }} onClick={this.progressivizeChild}>Contents</div>
@@ -1772,7 +1765,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                                 <div className="ribbon-toggle" style={{ backgroundColor: activeItem.scrollProgressivize ? PresColor.LightBlue : "" }} onClick={this.progressivizeScroll}>Scroll</div>
                                 <div className="ribbon-toggle" style={{ opacity: activeItem.scrollProgressivize ? 1 : 0.4, backgroundColor: targetDoc.editScrollProgressivize ? PresColor.LightBlue : "" }} onClick={this.editScrollProgressivize}>Edit</div>
                             </div>
-                        </div> */}
+                        </div>
                         <div className="ribbon-final-box">
                             Frames
                             <div className="ribbon-doubleButton">
diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx
index 23f0dbdee..0d1defbfe 100644
--- a/src/client/views/presentationview/PresElementBox.tsx
+++ b/src/client/views/presentationview/PresElementBox.tsx
@@ -326,7 +326,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
                         backgroundColor: this.props.styleProvider?.(this.layoutDoc, this.props.renderDepth, "color", this.props.layerProvider),
                         boxShadow: presBoxColor && presBoxColor !== "white" && presBoxColor !== "transparent" ? isSelected ? "0 0 0px 1.5px" + presBoxColor : undefined : undefined
                     }}>
-                    <div className="presItem-name" style={{ maxWidth: showMore ? (toolbarWidth - 185) : toolbarWidth - 95, cursor: isSelected ? 'text' : 'grab' }}>
+                    <div className="presItem-name" style={{ maxWidth: showMore ? (toolbarWidth - 195) : toolbarWidth - 105, cursor: isSelected ? 'text' : 'grab' }}>
                         <EditableView
                             ref={this._titleRef}
                             editing={!isSelected ? false : undefined}
-- 
cgit v1.2.3-70-g09d2


From 5f23e030769a4b5fdfc0bb7c965aa5cb2474a393 Mon Sep 17 00:00:00 2001
From: geireann <60007097+geireann@users.noreply.github.com>
Date: Mon, 30 Nov 2020 16:21:56 +0800
Subject: fixes and minor changes to temporal media settings in pres. trails

---
 src/client/views/.DS_Store                         | Bin 10244 -> 10244 bytes
 src/client/views/PropertiesView.tsx                |   2 +-
 src/client/views/nodes/PresBox.scss                |   3 +-
 src/client/views/nodes/PresBox.tsx                 | 117 ++++++++++-----------
 .../views/presentationview/PresElementBox.scss     |  66 ++++++------
 5 files changed, 92 insertions(+), 96 deletions(-)

(limited to 'src/client/views/PropertiesView.tsx')

diff --git a/src/client/views/.DS_Store b/src/client/views/.DS_Store
index c6f3afa14..60b336584 100644
Binary files a/src/client/views/.DS_Store and b/src/client/views/.DS_Store differ
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index bdba625f8..a9076fea7 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -1020,7 +1020,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                         <div className="propertiesView-presTrails-title"
                             onPointerDown={action(() => this.openPresProgressivize = !this.openPresProgressivize)}
                             style={{ backgroundColor: this.openPresProgressivize ? "black" : "" }}>
-                            &nbsp; <FontAwesomeIcon icon={"tasks"} /> &nbsp; Progressivize
+                            &nbsp; <FontAwesomeIcon style={{ alignSelf: "center" }} icon={"tasks"} /> &nbsp; Progressivize
                         <div className="propertiesView-presTrails-title-icon">
                                 <FontAwesomeIcon icon={this.openPresProgressivize ? "caret-down" : "caret-right"} size="lg" color="white" />
                             </div>
diff --git a/src/client/views/nodes/PresBox.scss b/src/client/views/nodes/PresBox.scss
index 6579dbf41..7cb304f13 100644
--- a/src/client/views/nodes/PresBox.scss
+++ b/src/client/views/nodes/PresBox.scss
@@ -1,6 +1,7 @@
 $light-blue: #AEDDF8;
 $dark-blue: #5B9FDD;
 $light-background: #ececec;
+$dark-grey: #656565;
 
 .presBox-cont {
     cursor: auto;
@@ -629,7 +630,7 @@ $light-background: #ececec;
         position: relative;
         font-size: 13;
         padding-bottom: 10px;
-        border-bottom: solid 1px darkgrey;
+        border-bottom: solid 1px $dark-grey;
 
         .presBox-dropdown:hover {
             border: solid 1px $dark-blue;
diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx
index 54818f67e..b1434f149 100644
--- a/src/client/views/nodes/PresBox.tsx
+++ b/src/client/views/nodes/PresBox.tsx
@@ -1367,7 +1367,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                     <div className={'presBox-ribbon'} onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
                         <div>
                             <div className="presBox-subheading">Range:</div>
-                            <div className={`slider-headers ${activeItem.presMovement === PresMovement.Pan || activeItem.presMovement === PresMovement.Zoom ? "" : "none"}`}>
+                            <div className={"slider-headers"}>
                                 <div className="slider-text">
                                     Start time:
                                 </div>
@@ -1378,6 +1378,52 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                                     End time:
                                 </div>
                             </div>
+                            <div className={"slider-headers"} style={{ marginTop: 0 }}>
+                                <div className="slider-text">
+                                    <input className="presBox-input"
+                                        style={{ textAlign: 'left', width: 30, height: 15, fontSize: 10 }}
+                                        type="number" value={NumCast(activeItem.presStartTime)}
+                                        onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { activeItem.presStartTime = Number(e.target.value); })}
+                                    /> s
+                                    </div>
+                                <div className="slider-text">
+                                    {Math.round((NumCast(activeItem.presEndTime) - NumCast(activeItem.presStartTime)) * 10) / 10} s
+                                </div>
+                                <div className="slider-text">
+                                    <input className="presBox-input"
+                                        style={{ textAlign: 'right', width: 30, height: 15, fontSize: 10 }}
+                                        type="number" value={NumCast(activeItem.presEndTime)}
+                                        onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { activeItem.presEndTime = Number(e.target.value); })}
+                                    /> s
+                                </div>
+                            </div>
+                            <div className="multiThumb-slider">
+                                <input type="range" step="0.1" min="0" max={activeItem.type === DocumentType.AUDIO ? Math.round(NumCast(activeItem.duration) * 10) / 10 : Math.round(NumCast(activeItem["data-duration"]) * 10) / 10} value={NumCast(activeItem.presEndTime)}
+                                    style={{ gridColumn: 1, gridRow: 1 }}
+                                    className={`toolbar-slider ${"end"}`}
+                                    id="toolbar-slider"
+                                    onPointerDown={() => this._batch = UndoManager.StartBatch("presEndTime")}
+                                    onPointerUp={() => this._batch?.end()}
+                                    onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
+                                        e.stopPropagation();
+                                        activeItem.presEndTime = Number(e.target.value);
+                                    }} />
+                                <input type="range" step="0.1" min="0" max={activeItem.type === DocumentType.AUDIO ? Math.round(NumCast(activeItem.duration) * 10) / 10 : Math.round(NumCast(activeItem["data-duration"]) * 10) / 10} value={NumCast(activeItem.presStartTime)}
+                                    style={{ gridColumn: 1, gridRow: 1 }}
+                                    className={`toolbar-slider ${"start"}`}
+                                    id="toolbar-slider"
+                                    onPointerDown={() => this._batch = UndoManager.StartBatch("presEndTime")}
+                                    onPointerUp={() => this._batch?.end()}
+                                    onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
+                                        e.stopPropagation();
+                                        activeItem.presStartTime = Number(e.target.value);
+                                    }} />
+                            </div>
+                            <div className={`slider-headers ${activeItem.presMovement === PresMovement.Pan || activeItem.presMovement === PresMovement.Zoom ? "" : "none"}`}>
+                                <div className="slider-text">0 s</div>
+                                <div className="slider-text"></div>
+                                <div className="slider-text">{activeItem.type === DocumentType.AUDIO ? Math.round(NumCast(activeItem.duration) * 10) / 10 : Math.round(NumCast(activeItem["data-duration"]) * 10) / 10} s</div>
+                            </div>
                             <div className="presBox-subheading">Start playing:</div>
                             <div className="presBox-radioButtons">
                                 <div className="checkbox-container">
@@ -1425,69 +1471,18 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                                     {activeItem.mediaStop !== "afterSlide" ?
                                             (null)
                                             :
-                                            <div className="presBox-dropdown" onClick={action(e => { e.stopPropagation(); this.openMovementDropdown = !this.openMovementDropdown; })} style={{ borderBottomLeftRadius: this.openMovementDropdown ? 0 : 5, border: this.openMovementDropdown ? `solid 2px ${PresColor.DarkBlue}` : 'solid 1px black' }}>
-                                                {this.setMovementName(activeItem.presMovement, activeItem)}
-                                                <FontAwesomeIcon className='presBox-dropdownIcon' style={{ gridColumn: 2, color: this.openMovementDropdown ? PresColor.DarkBlue : 'black' }} icon={"angle-down"} />
-                                                <div className={'presBox-dropdownOptions'} id={'presBoxMovementDropdown'} onPointerDown={e => e.stopPropagation()} style={{ display: this.openMovementDropdown ? "grid" : "none" }}>
-                                                    <div className={`presBox-dropdownOption ${activeItem.presMovement === PresMovement.None ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.None)}>None</div>
-                                                    <div className={`presBox-dropdownOption ${activeItem.presMovement === PresMovement.Zoom ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.Zoom)}>Pan {"&"} Zoom</div>
-                                                    <div className={`presBox-dropdownOption ${activeItem.presMovement === PresMovement.Pan ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.Pan)}>Pan</div>
-                                                    <div className={`presBox-dropdownOption ${activeItem.presMovement === PresMovement.Jump ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.Jump)}>Jump cut</div>
-                                                </div>
-                                            </div>}
-                                    </div>
-                                </div>
-                            </div>
-                            <div className={`slider-headers ${activeItem.presMovement === PresMovement.Pan || activeItem.presMovement === PresMovement.Zoom ? "" : "none"}`}>
-                                <div className="slider-text">
-                                    <div className="ribbon-property" style={{ paddingRight: 0, paddingLeft: 0 }}>
-                                        <input className="presBox-input"
-                                            style={{ textAlign: 'left', width: 50 }}
-                                            type="number" value={NumCast(activeItem.presStartTime)}
-                                            onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { activeItem.presStartTime = Number(e.target.value); })}
-                                        /> s
-                                    </div>
-                                </div>
-                                <div className="slider-text">
-                                    {Math.round((NumCast(activeItem.presEndTime) - NumCast(activeItem.presStartTime)) * 10) / 10} s
-                                </div>
-                                <div className="slider-text">
-                                    <div className="ribbon-property" style={{ paddingRight: 0, paddingLeft: 0 }}>
-                                        <input className="presBox-input"
-                                            style={{ textAlign: 'right', width: 50 }}
-                                            type="number" value={NumCast(activeItem.presEndTime)}
-                                            onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { activeItem.presEndTime = Number(e.target.value); })}
-                                        /> s
+                                            <></>
+                                            // <select className="presBox-viewPicker"
+                                            //     style={{ display: this.layoutDoc.presStatus === "edit" ? "block" : "none" }}
+                                            //     onPointerDown={e => e.stopPropagation()}
+                                            //     onChange={this.viewChanged}
+                                            //     value={}>
+                                            //     {this.mediaEn}
+                                            // </select>}
+                                        }
                                     </div>
                                 </div>
                             </div>
-                            <div className="multiThumb-slider">
-                                <input type="range" step="0.1" min="0" max={activeItem.type === DocumentType.AUDIO ? Math.round(NumCast(activeItem.duration) * 10) / 10 : Math.round(NumCast(activeItem["data-duration"]) * 10) / 10} value={NumCast(activeItem.presEndTime)}
-                                    style={{ gridColumn: 1, gridRow: 1 }}
-                                    className={`toolbar-slider ${"end"}`}
-                                    id="toolbar-slider"
-                                    onPointerDown={() => this._batch = UndoManager.StartBatch("presEndTime")}
-                                    onPointerUp={() => this._batch?.end()}
-                                    onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
-                                        e.stopPropagation();
-                                        activeItem.presEndTime = Number(e.target.value);
-                                    }} />
-                                <input type="range" step="0.1" min="0" max={activeItem.type === DocumentType.AUDIO ? Math.round(NumCast(activeItem.duration) * 10) / 10 : Math.round(NumCast(activeItem["data-duration"]) * 10) / 10} value={NumCast(activeItem.presStartTime)}
-                                    style={{ gridColumn: 1, gridRow: 1 }}
-                                    className={`toolbar-slider ${"start"}`}
-                                    id="toolbar-slider"
-                                    onPointerDown={() => this._batch = UndoManager.StartBatch("presEndTime")}
-                                    onPointerUp={() => this._batch?.end()}
-                                    onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
-                                        e.stopPropagation();
-                                        activeItem.presStartTime = Number(e.target.value);
-                                    }} />
-                            </div>
-                            <div className={`slider-headers ${activeItem.presMovement === PresMovement.Pan || activeItem.presMovement === PresMovement.Zoom ? "" : "none"}`}>
-                                <div className="slider-text">0 s</div>
-                                <div className="slider-text"></div>
-                                <div className="slider-text">{activeItem.type === DocumentType.AUDIO ? Math.round(NumCast(activeItem.duration) * 10) / 10 : Math.round(NumCast(activeItem["data-duration"]) * 10) / 10} s</div>
-                            </div>
                         </div>
                         {/* <div className="ribbon-box">
                             <div className="ribbon-doubleButton" style={{ display: targetDoc.type === DocumentType.AUDIO ? "inline-flex" : "none" }}>
diff --git a/src/client/views/presentationview/PresElementBox.scss b/src/client/views/presentationview/PresElementBox.scss
index e1eeefc30..1ad4b820e 100644
--- a/src/client/views/presentationview/PresElementBox.scss
+++ b/src/client/views/presentationview/PresElementBox.scss
@@ -157,39 +157,39 @@ $slide-active: #5B9FDD;
 }
 
 // .presItem-slide:hover {
-    //     .presItem-slideButtons {
-    //         display: flex;
-    //         grid-column: 7;
-    //         grid-row: 1/3;
-    //         width: max-content;
-    //         justify-self: right;
-    //         justify-content: flex-end;
-
-    //         .slideButton {
-    //             cursor: pointer;
-    //             position: relative;
-    //             border-radius: 100px;
-    //             z-index: 300;
-    //             width: 18px;
-    //             height: 18px;
-    //             display: flex;
-    //             font-size: 12px;
-    //             justify-self: center;
-    //             align-self: center;
-    //             background-color: rgba(0, 0, 0, 0.5);
-    //             color: white;
-    //             justify-content: center;
-    //             align-items: center;
-    //             transition: 0.2s;
-    //             margin-right: 3px;
-    //         }
-
-    //         .slideButton:hover {
-    //             background-color: rgba(0, 0, 0, 1);
-    //             transform: scale(1.2);
-    //         }
-    //     }
-    // }
+//     .presItem-slideButtons {
+//         display: flex;
+//         grid-column: 7;
+//         grid-row: 1/3;
+//         width: max-content;
+//         justify-self: right;
+//         justify-content: flex-end;
+
+//         .slideButton {
+//             cursor: pointer;
+//             position: relative;
+//             border-radius: 100px;
+//             z-index: 300;
+//             width: 18px;
+//             height: 18px;
+//             display: flex;
+//             font-size: 12px;
+//             justify-self: center;
+//             align-self: center;
+//             background-color: rgba(0, 0, 0, 0.5);
+//             color: white;
+//             justify-content: center;
+//             align-items: center;
+//             transition: 0.2s;
+//             margin-right: 3px;
+//         }
+
+//         .slideButton:hover {
+//             background-color: rgba(0, 0, 0, 1);
+//             transform: scale(1.2);
+//         }
+//     }
+// }
 
 .presItem-slide.active {
     box-shadow: 0 0 0px 1.5px $dark-blue;
-- 
cgit v1.2.3-70-g09d2


From 69f247903d289aeac6383ba3a6912504a6172873 Mon Sep 17 00:00:00 2001
From: geireann <60007097+geireann@users.noreply.github.com>
Date: Wed, 2 Dec 2020 18:34:23 +0800
Subject: loader progress bar (superficial)

- temp media changes
---
 deploy/index.html                   |  83 +++++++++---
 deploy/loader.css                   | 141 ---------------------
 src/client/views/MainView.tsx       |  12 +-
 src/client/views/PropertiesView.tsx |   4 +-
 src/client/views/nodes/PresBox.scss |  18 ++-
 src/client/views/nodes/PresBox.tsx  | 245 +++++++++++++++++++-----------------
 6 files changed, 226 insertions(+), 277 deletions(-)
 delete mode 100644 deploy/loader.css

(limited to 'src/client/views/PropertiesView.tsx')

diff --git a/deploy/index.html b/deploy/index.html
index beb7dd205..4e0c2dfa4 100644
--- a/deploy/index.html
+++ b/deploy/index.html
@@ -13,20 +13,51 @@
             align-content: center;
             justify-content: center;
             background-color: #AEDDF8;
+            transition: 3s;
             z-index: 10;
             width: 100vw;
             height: 100vh;
         }
 
         .dash-loader-container {
-            width: 20vw;
-            height: 20vw;
+            display: grid;
+            grid-auto-rows: auto 30px auto;
+        }
+
+        .dash-progress-bar {
+            width: 200px;
+            height: 5px;
+            align-self: center;
+            margin-top: 20px;
+            background-color: #ececec;
+            border-radius: 5px;
+            overflow: hidden;
+        }
+
+        .dash-progress {
+            width: 0%;
+            height: 20px;
+            background-color: #5b9fdd;
+            transition: 0.1s;
+        }
+
+        .dash-animation-container {
+            width: 10vw;
+            height: 10vw;
             display: flex;
             align-items: center;
             justify-content: center;
             border-radius: 100%;
             background-color: #5B9FDD;
-            align-self: center;
+            justify-self: center;
+            align-self: flex-end;
+        }
+
+        .dash-loader-text {
+            font-size: 15px;
+            font-family: "Roboto";
+            text-align: center;
+            color: #5B9FDD;
         }
 
         .dash-d-path {
@@ -38,41 +69,63 @@
         @keyframes dash-d-path {
             0% {
                 stroke-dashoffset: 1000;
-                /* stroke-width: 0px; */
             }
 
             20% {
                 stroke-dashoffset: 0;
-                /* stroke-width: 20px; */
             }
 
             70% {
                 stroke-dashoffset: 0;
-                /* stroke-width: 20px; */
             }
 
             90% {
                 stroke-dashoffset: 1000;
-                /* stroke-width: 0px; */
             }
 
             100% {
                 stroke-dashoffset: 1000;
-                /* stroke-width: 0px; */
             }
         }
     </style>
 </head>
 
 <body style="display:flex" id="dash-body">
-    <div class="dash-loader" id="loader" style="z-index:10; width:100%; height:100%">
+    <div class="dash-loader" id="loader" style="z-index:10; width:100%; height:100%;">
         <div class="dash-loader-container">
-            <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200px"
-                height="200px" viewBox="0 0 250 350">
-                <path class="dash-d-path" fill-rule="evenodd" stroke="#ececec" stroke-width="20px" stroke-linecap="butt"
-                    stroke-linejoin="miter" fill="none"
-                    d="M196.500,18.500 C195.888,79.462 194.655,160.273 197.500,195.500 C198.117,203.144 199.664,225.773 189.500,246.500 C183.949,257.819 175.192,268.535 163.500,277.500 C147.404,289.842 133.006,294.212 121.500,295.500 C106.618,297.166 92.057,294.673 79.500,288.500 C68.970,283.324 58.384,274.780 49.500,261.500 C39.958,247.237 35.188,230.375 35.500,213.500 C35.760,199.463 39.572,185.692 46.500,173.500 C55.433,157.780 65.945,148.829 75.500,143.500 C85.352,138.005 98.187,134.141 114.500,134.500 C128.982,134.819 143.177,139.076 155.500,146.500 C186.160,164.973 196.208,196.242 197.500,216.500 C197.663,219.061 197.578,222.985 197.500,226.500 C197.092,244.967 195.719,262.030 195.500,280.500 C195.460,283.898 195.500,293.783 195.500,300.500 C195.500,304.834 195.500,309.189 195.500,313.500 " />
-            </svg>
+            <div class="dash-animation-container">
+                <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100px"
+                    height="100px" viewBox="0 0 250 350">
+                    <path class="dash-d-path" fill-rule="evenodd" stroke="#ececec" stroke-width="30px"
+                        stroke-linecap="butt" stroke-linejoin="miter" fill="none"
+                        d="M196.500,18.500 C195.888,79.462 194.655,160.273 197.500,195.500 C198.117,203.144 199.664,225.773 189.500,246.500 C183.949,257.819 175.192,268.535 163.500,277.500 C147.404,289.842 133.006,294.212 121.500,295.500 C106.618,297.166 92.057,294.673 79.500,288.500 C68.970,283.324 58.384,274.780 49.500,261.500 C39.958,247.237 35.188,230.375 35.500,213.500 C35.760,199.463 39.572,185.692 46.500,173.500 C55.433,157.780 65.945,148.829 75.500,143.500 C85.352,138.005 98.187,134.141 114.500,134.500 C128.982,134.819 143.177,139.076 155.500,146.500 C186.160,164.973 196.208,196.242 197.500,216.500 C197.663,219.061 197.578,222.985 197.500,226.500 C197.092,244.967 195.719,262.030 195.500,280.500 C195.460,283.898 195.500,293.783 195.500,300.500 C195.500,304.834 195.500,309.189 195.500,313.500 " />
+                </svg>
+            </div>
+            <div class="dash-progress-bar">
+                <div id="dash-progress" class="dash-progress">
+                </div>
+                <script>
+                    setTimeout(() => {
+                        document.getElementById("dash-progress").style.width = "10%"
+                        document.getElementById("dash-loader-text").innerHTML = "Loading Dash..."
+                    }, 500);
+                    setTimeout(() => {
+                        document.getElementById("dash-progress").style.width = "30%"
+                        document.getElementById("dash-loader-text").innerHTML = "Preparing dashboards..."
+                    }, 1000);
+                    setTimeout(() => {
+                        document.getElementById("dash-progress").style.width = "50%"
+                        document.getElementById("dash-loader-text").innerHTML = "Fetching documents..."
+                    }, 1500);
+                    setTimeout(() => {
+                        document.getElementById("dash-progress").style.width = "70%"
+                        document.getElementById("dash-loader-text").innerHTML = "Finalising setup..."
+                    }, 3000);
+                </script>
+            </div>
+            <div id="dash-loader-text" class="dash-loader-text">
+                Loading Dash...
+            </div>
         </div>
     </div>
     <!-- <script src="https://hypothes.is/embed.js" async></script> -->
diff --git a/deploy/loader.css b/deploy/loader.css
deleted file mode 100644
index 065862013..000000000
--- a/deploy/loader.css
+++ /dev/null
@@ -1,141 +0,0 @@
-.dash-loader {
-    display: flex;
-    align-content: center;
-    justify-content: center;
-    background-color: lightcyan;
-    z-index: 10;
-    width: 100%;
-    height: 100%;
-}
-
-.dash-loader-container {
-    width: 100;
-    align-self: center;
-}
-
-.dash-d-path {
-    stroke-dasharray: 1000;
-    stroke-dashoffset: 1000;
-    animation: dash-d-path 10s linear infinite;
-}
-
-@keyframes dash-d-path {
-    0% {
-        stroke-dashoffset: 1000;
-        /* stroke-width: 0px; */
-    }
-
-    10% {
-        stroke-dashoffset: 0;
-        /* stroke-width: 20px; */
-    }
-
-    90% {
-        stroke-dashoffset: 0;
-        /* stroke-width: 20px; */
-    }
-
-    100% {
-        stroke-dashoffset: 1000;
-        /* stroke-width: 0px; */
-    }
-}
-
-.dash-a-path {
-    stroke-dasharray: 1000;
-    stroke-dashoffset: 1000;
-    animation: dash-a-path 10s linear infinite;
-}
-
-@keyframes dash-a-path {
-    0% {
-        stroke-dashoffset: 1000;
-        /* stroke-width: 0px; */
-    }
-
-    7% {
-        stroke-dashoffset: 1000;
-        /* stroke-width: 0px; */
-    }
-
-    17% {
-        stroke-dashoffset: 0;
-        /* stroke-width: 20px; */
-    }
-
-    90% {
-        stroke-dashoffset: 0;
-        /* stroke-width: 20px; */
-    }
-
-    100% {
-        stroke-dashoffset: 1000;
-        /* stroke-width: 0px; */
-    }
-}
-
-.dash-s-path {
-    stroke-dasharray: 1000;
-    stroke-dashoffset: 1000;
-    animation: dash-s-path 10s linear infinite;
-}
-
-@keyframes dash-s-path {
-    0% {
-        stroke-dashoffset: 1000;
-        /* stroke-width: 0px; */
-    }
-
-    14% {
-        stroke-dashoffset: 1000;
-        /* stroke-width: 0px; */
-    }
-
-    20% {
-        stroke-dashoffset: 0;
-        /* stroke-width: 20px; */
-    }
-
-    90% {
-        stroke-dashoffset: 0;
-        /* stroke-width: 20px; */
-    }
-
-    100% {
-        stroke-dashoffset: 1000;
-        /* stroke-width: 0px; */
-    }
-}
-
-.dash-h-path {
-    stroke-dasharray: 1000;
-    stroke-dashoffset: 1000;
-    animation: dash-h-path 10s linear infinite;
-}
-
-@keyframes dash-h-path {
-    0% {
-        stroke-dashoffset: 1000;
-        /* stroke-width: 0px; */
-    }
-
-    18% {
-        stroke-dashoffset: 1000;
-        /* stroke-width: 0px; */
-    }
-
-    28% {
-        stroke-dashoffset: 0;
-        /* stroke-width: 20px; */
-    }
-
-    90% {
-        stroke-dashoffset: 0;
-        /* stroke-width: 20px; */
-    }
-
-    100% {
-        stroke-dashoffset: 1000;
-        /* stroke-width: 0px; */
-    }
-}
\ No newline at end of file
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 12e361dc1..747bde64d 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -87,11 +87,15 @@ export class MainView extends React.Component {
     componentDidMount() {
         document.getElementById("root")?.addEventListener("scroll", e => ((ele) => ele.scrollLeft = ele.scrollTop = 0)(document.getElementById("root")!));
         const ele = document.getElementById("loader");
-
-        if (ele) {
+        const prog = document.getElementById("dash-progress");
+        if (ele && prog) {
             // remove from DOM
-            setTimeout(() => { ele.style.opacity = "0"; }, 0);
-            setTimeout(() => ele.outerHTML = '', 10000);
+            setTimeout(() => {
+                clearTimeout();
+                prog.style.transition = "1s";
+                prog.style.width = "100%";
+            }, 0);
+            setTimeout(() => ele.outerHTML = '', 1000);
         }
         new InkStrokeProperties();
         this._sidebarContent.proto = undefined;
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index a9076fea7..3c77bc309 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -1016,7 +1016,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                             {PresBox.Instance.transitionDropdown}
                         </div> : null}
                     </div>}
-                    {!selectedItem || type === DocumentType.VID || type === DocumentType.AUDIO ? (null) : <div className="propertiesView-presTrails">
+                    {/* {!selectedItem || type === DocumentType.VID || type === DocumentType.AUDIO ? (null) : <div className="propertiesView-presTrails">
                         <div className="propertiesView-presTrails-title"
                             onPointerDown={action(() => this.openPresProgressivize = !this.openPresProgressivize)}
                             style={{ backgroundColor: this.openPresProgressivize ? "black" : "" }}>
@@ -1028,7 +1028,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                         {this.openPresProgressivize ? <div className="propertiesView-presTrails-content">
                             {PresBox.Instance.progressivizeDropdown}
                         </div> : null}
-                    </div>}
+                    </div>} */}
                     {!selectedItem || (type !== DocumentType.VID && type !== DocumentType.AUDIO) ? (null) : <div className="propertiesView-presTrails">
                         <div className="propertiesView-presTrails-title"
                             onPointerDown={action(() => { this.openSlideOptions = !this.openSlideOptions; })}
diff --git a/src/client/views/nodes/PresBox.scss b/src/client/views/nodes/PresBox.scss
index ba21cef42..1ba86232b 100644
--- a/src/client/views/nodes/PresBox.scss
+++ b/src/client/views/nodes/PresBox.scss
@@ -129,7 +129,9 @@ $dark-grey: #656565;
 }
 
 .presBox-radioButtons {
-    background-color: rgba(0, 0, 0, 0.1);
+    font-size: 10px;
+    font-weight: 200;
+    // background-color: rgba(0, 0, 0, 0.1);
 
     .checkbox-container {
         margin-left: 10px;
@@ -345,6 +347,20 @@ $dark-grey: #656565;
         font-weight: 100;
         margin-top: 3px;
         font-size: 10px;
+
+        .slider-block {
+            width: 63px;
+            border-radius: 5px;
+            text-align: center;
+            margin-bottom: 8px;
+            margin-top: 8px;
+        }
+
+        .slider-number {
+            border-radius: 3px;
+            width: 30px;
+            margin: auto;
+        }
     }
 
     .slider-value {
diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx
index d21e1603d..a4f79571e 100644
--- a/src/client/views/nodes/PresBox.tsx
+++ b/src/client/views/nodes/PresBox.tsx
@@ -640,10 +640,14 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         if (this.childDocs[stopDocIndex - 1].mediaStopTriggerList) {
             const list = DocListCast(this.childDocs[stopDocIndex - 1].mediaStopTriggerList);
             list.push(activeItem);
+            // this.childDocs[stopDocIndex - 1].mediaStopTriggerList = list;
+            console.log(list);
         } else {
             this.childDocs[stopDocIndex - 1].mediaStopTriggerList = new List<Doc>();
             const list = DocListCast(this.childDocs[stopDocIndex - 1].mediaStopTriggerList);
             list.push(activeItem);
+            // this.childDocs[stopDocIndex - 1].mediaStopTriggerList = list;
+            console.log(list);
         }
     });
 
@@ -1424,102 +1428,138 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                 <div>
                     <div className={'presBox-ribbon'} onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
                         <div>
-                            <div className="presBox-subheading">Range:</div>
-                            <div className={"slider-headers"}>
-                                <div className="slider-text">
-                                    Start time:
-                                </div>
-                                <div className="slider-text">
-                                    Duration:
-                                </div>
-                                <div className="slider-text">
-                                    End time:
-                                </div>
-                            </div>
-                            <div className={"slider-headers"} style={{ marginTop: 0 }}>
-                                <div className="slider-text">
-                                    <input className="presBox-input"
-                                        style={{ textAlign: 'left', width: 30, height: 15, fontSize: 10 }}
-                                        type="number" value={NumCast(activeItem.presStartTime)}
-                                        onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { activeItem.presStartTime = Number(e.target.value); })}
-                                    /> s
+                            <div className="ribbon-box">
+                                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={{ backgroundColor: PresColor.LightBackground }}>
+                                            <input className="presBox-input"
+                                                style={{ textAlign: 'center', width: 30, height: 15, fontSize: 10 }}
+                                                type="number" value={NumCast(activeItem.presStartTime)}
+                                                onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { activeItem.presStartTime = Number(e.target.value); })}
+                                            />
+                                        </div>
+                                    </div>
+                                    <div className="slider-block">
+                                        <div className="slider-text" style={{ fontWeight: 500 }}>
+                                            Duration (s)
+                                        </div>
+                                        <div className="slider-number" style={{ backgroundColor: PresColor.LightBlue }}>
+                                            {Math.round((NumCast(activeItem.presEndTime) - NumCast(activeItem.presStartTime)) * 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={{ backgroundColor: PresColor.LightBackground }}>
+                                            <input className="presBox-input"
+                                                style={{ textAlign: 'center', width: 30, height: 15, fontSize: 10 }}
+                                                type="number" value={NumCast(activeItem.presEndTime)}
+                                                onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { activeItem.presEndTime = Number(e.target.value); })}
+                                            />
+                                        </div>
                                     </div>
-                                <div className="slider-text">
-                                    {Math.round((NumCast(activeItem.presEndTime) - NumCast(activeItem.presStartTime)) * 10) / 10} s
                                 </div>
-                                <div className="slider-text">
-                                    <input className="presBox-input"
-                                        style={{ textAlign: 'right', width: 30, height: 15, fontSize: 10 }}
-                                        type="number" value={NumCast(activeItem.presEndTime)}
-                                        onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { activeItem.presEndTime = Number(e.target.value); })}
-                                    /> s
+                                <div className="multiThumb-slider">
+                                    <input type="range" step="0.1" min="0" max={activeItem.type === DocumentType.AUDIO ? Math.round(NumCast(activeItem.duration) * 10) / 10 : Math.round(NumCast(activeItem["data-duration"]) * 10) / 10} value={NumCast(activeItem.presEndTime)}
+                                        style={{ gridColumn: 1, gridRow: 1 }}
+                                        className={`toolbar-slider ${"end"}`}
+                                        id="toolbar-slider"
+                                        onPointerDown={() => {
+                                            this._batch = UndoManager.StartBatch("presEndTime");
+                                            const endBlock = document.getElementById("endTime");
+                                            if (endBlock) {
+                                                endBlock.style.color = PresColor.LightBackground;
+                                                endBlock.style.backgroundColor = PresColor.DarkBlue;
+                                            }
+                                        }}
+                                        onPointerUp={() => {
+                                            this._batch?.end();
+                                            const endBlock = document.getElementById("endTime");
+                                            if (endBlock) {
+                                                endBlock.style.color = "black";
+                                                endBlock.style.backgroundColor = PresColor.LightBackground;
+                                            }
+                                        }}
+                                        onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
+                                            e.stopPropagation();
+                                            activeItem.presEndTime = Number(e.target.value);
+                                        }} />
+                                    <input type="range" step="0.1" min="0" max={activeItem.type === DocumentType.AUDIO ? Math.round(NumCast(activeItem.duration) * 10) / 10 : Math.round(NumCast(activeItem["data-duration"]) * 10) / 10} value={NumCast(activeItem.presStartTime)}
+                                        style={{ gridColumn: 1, gridRow: 1 }}
+                                        className={`toolbar-slider ${"start"}`}
+                                        id="toolbar-slider"
+                                        onPointerDown={() => {
+                                            this._batch = UndoManager.StartBatch("presStartTime");
+                                            const startBlock = document.getElementById("startTime");
+                                            if (startBlock) {
+                                                startBlock.style.color = PresColor.LightBackground;
+                                                startBlock.style.backgroundColor = PresColor.DarkBlue;
+                                            }
+                                        }}
+                                        onPointerUp={() => {
+                                            this._batch?.end();
+                                            const startBlock = document.getElementById("startTime");
+                                            if (startBlock) {
+                                                startBlock.style.color = "black";
+                                                startBlock.style.backgroundColor = PresColor.LightBackground;
+                                            }
+                                        }}
+                                        onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
+                                            e.stopPropagation();
+                                            activeItem.presStartTime = Number(e.target.value);
+                                        }} />
                                 </div>
-                            </div>
-                            <div className="multiThumb-slider">
-                                <input type="range" step="0.1" min="0" max={activeItem.type === DocumentType.AUDIO ? Math.round(NumCast(activeItem.duration) * 10) / 10 : Math.round(NumCast(activeItem["data-duration"]) * 10) / 10} value={NumCast(activeItem.presEndTime)}
-                                    style={{ gridColumn: 1, gridRow: 1 }}
-                                    className={`toolbar-slider ${"end"}`}
-                                    id="toolbar-slider"
-                                    onPointerDown={() => this._batch = UndoManager.StartBatch("presEndTime")}
-                                    onPointerUp={() => this._batch?.end()}
-                                    onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
-                                        e.stopPropagation();
-                                        activeItem.presEndTime = Number(e.target.value);
-                                    }} />
-                                <input type="range" step="0.1" min="0" max={activeItem.type === DocumentType.AUDIO ? Math.round(NumCast(activeItem.duration) * 10) / 10 : Math.round(NumCast(activeItem["data-duration"]) * 10) / 10} value={NumCast(activeItem.presStartTime)}
-                                    style={{ gridColumn: 1, gridRow: 1 }}
-                                    className={`toolbar-slider ${"start"}`}
-                                    id="toolbar-slider"
-                                    onPointerDown={() => this._batch = UndoManager.StartBatch("presEndTime")}
-                                    onPointerUp={() => this._batch?.end()}
-                                    onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
-                                        e.stopPropagation();
-                                        activeItem.presStartTime = Number(e.target.value);
-                                    }} />
-                            </div>
-                            <div className={`slider-headers ${activeItem.presMovement === PresMovement.Pan || activeItem.presMovement === PresMovement.Zoom ? "" : "none"}`}>
-                                <div className="slider-text">0 s</div>
-                                <div className="slider-text"></div>
-                                <div className="slider-text">{activeItem.type === DocumentType.AUDIO ? Math.round(NumCast(activeItem.duration) * 10) / 10 : Math.round(NumCast(activeItem["data-duration"]) * 10) / 10} s</div>
-                            </div>
-                            <div className="presBox-subheading">Start playing:</div>
-                            <div className="presBox-radioButtons">
-                                <div className="checkbox-container">
-                                    <input className="presBox-checkbox"
-                                        type="checkbox"
-                                        onChange={() => activeItem.mediaStart = "manual"}
-                                        checked={activeItem.mediaStart === "manual"}
-                                    />
-                                    <div>On click</div>
-                                </div>
-                                <div className="checkbox-container">
-                                    <input className="presBox-checkbox"
-                                        type="checkbox"
-                                        onChange={() => activeItem.mediaStart = "auto"}
-                                        checked={activeItem.mediaStart === "auto"}
-                                    />
-                                    <div>Automatically</div>
+                                <div className={`slider-headers ${activeItem.presMovement === PresMovement.Pan || activeItem.presMovement === PresMovement.Zoom ? "" : "none"}`}>
+                                    <div className="slider-text">0 s</div>
+                                    <div className="slider-text"></div>
+                                    <div className="slider-text">{activeItem.type === DocumentType.AUDIO ? Math.round(NumCast(activeItem.duration) * 10) / 10 : Math.round(NumCast(activeItem["data-duration"]) * 10) / 10} s</div>
                                 </div>
                             </div>
-                            <div className="presBox-subheading">Stop playing:</div>
-                            <div className="presBox-radioButtons">
-                                <div className="checkbox-container">
-                                    <input className="presBox-checkbox"
-                                        type="checkbox"
-                                        onChange={() => activeItem.mediaStop = "manual"}
-                                        checked={activeItem.mediaStop === "manual"}
-                                    />
-                                    <div>At audio end time</div>
-                                </div>
-                                <div className="checkbox-container">
-                                    <input className="presBox-checkbox"
-                                        type="checkbox"
-                                        onChange={() => activeItem.mediaStop = "auto"}
-                                        checked={activeItem.mediaStop === "auto"}
-                                    />
-                                    <div>On slide change</div>
+                            <div className="ribbon-final-box">
+                                Playback
+                                <div className="presBox-subheading">Start playing:</div>
+                                <div className="presBox-radioButtons">
+                                    <div className="checkbox-container">
+                                        <input className="presBox-checkbox"
+                                            type="checkbox"
+                                            onChange={() => activeItem.mediaStart = "manual"}
+                                            checked={activeItem.mediaStart === "manual"}
+                                        />
+                                        <div>On click</div>
+                                    </div>
+                                    <div className="checkbox-container">
+                                        <input className="presBox-checkbox"
+                                            type="checkbox"
+                                            onChange={() => activeItem.mediaStart = "auto"}
+                                            checked={activeItem.mediaStart === "auto"}
+                                        />
+                                        <div>Automatically</div>
+                                    </div>
                                 </div>
-                                <div className="checkbox-container">
+                                <div className="presBox-subheading">Stop playing:</div>
+                                <div className="presBox-radioButtons">
+                                    <div className="checkbox-container">
+                                        <input className="presBox-checkbox"
+                                            type="checkbox"
+                                            onChange={() => activeItem.mediaStop = "manual"}
+                                            checked={activeItem.mediaStop === "manual"}
+                                        />
+                                        <div>At audio end time</div>
+                                    </div>
+                                    <div className="checkbox-container">
+                                        <input className="presBox-checkbox"
+                                            type="checkbox"
+                                            onChange={() => activeItem.mediaStop = "auto"}
+                                            checked={activeItem.mediaStop === "auto"}
+                                        />
+                                        <div>On slide change</div>
+                                    </div>
+                                    {/* <div className="checkbox-container">
                                     <input className="presBox-checkbox"
                                         type="checkbox"
                                         onChange={() => activeItem.mediaStop = "afterSlide"}
@@ -1535,33 +1575,10 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                                             {this.mediaStopSlides}
                                         </select>
                                     </div>
+                                </div> */}
                                 </div>
                             </div>
                         </div>
-                        {/* <div className="ribbon-box">
-                            <div className="ribbon-doubleButton" style={{ display: targetDoc.type === DocumentType.AUDIO ? "inline-flex" : "none" }}>
-                                <div className="ribbon-toggle" style={{ backgroundColor: activeItem.playAuto ? PresColor.LightBlue : "" }} onClick={() => activeItem.playAuto = !activeItem.playAuto}>Play automatically</div>
-                                <div className="ribbon-toggle" style={{ display: "flex", backgroundColor: activeItem.playAuto ? "" : PresColor.LightBlue }} onClick={() => activeItem.playAuto = !activeItem.playAuto}>Play on next</div>
-                            </div>
-                            {targetDoc.type === DocumentType.AUDIO ? <div className="ribbon-doubleButton" style={{ marginRight: 10 }}>
-                                <div className="presBox-subheading">Start time</div>
-                                <div className="ribbon-property" style={{ paddingRight: 0, paddingLeft: 0 }}>
-                                    <input className="presBox-input"
-                                        style={{ textAlign: 'left', width: 50 }}
-                                        type="number" value={NumCast(activeItem.presStartTime)}
-                                        onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { activeItem.presStartTime = Number(e.target.value); })} />
-                                </div>
-                            </div> : (null)}
-                            {targetDoc.type === DocumentType.AUDIO ? <div className="ribbon-doubleButton" style={{ marginRight: 10 }}>
-                                <div className="presBox-subheading">End time</div>
-                                <div className="ribbon-property" style={{ paddingRight: 0, paddingLeft: 0 }}>
-                                    <input className="presBox-input"
-                                        style={{ textAlign: 'left', width: 50 }}
-                                        type="number" value={NumCast(activeItem.presEndTime)}
-                                        onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { const val = e.target.value; activeItem.presEndTime = Number(val); })} />
-                                </div>
-                            </div> : (null)}
-                        </div> */}
                     </div>
                 </div >
             );
-- 
cgit v1.2.3-70-g09d2

