From 3c8cb517c811f94dce1e3d8430e07af316642365 Mon Sep 17 00:00:00 2001
From: sotech117 <michael_foiani@brown.edu>
Date: Thu, 13 Apr 2023 05:39:21 -0400
Subject: Compile and make compatible all the scattered code I had for
 empowering trails for dash meeting. Still much to do with ui, but basic
 functionaltiy is there. Two key things, 1) navigation for branching trails,
 and 2) ability to runSubroutines on tested trails.

---
 src/client/views/collections/TreeView.tsx | 51 +++++++++++++++++++++++++++++--
 1 file changed, 49 insertions(+), 2 deletions(-)

(limited to 'src/client/views/collections/TreeView.tsx')

diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 75e76019e..153c2c71a 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -227,6 +227,37 @@ export class TreeView extends React.Component<TreeViewProps> {
         }
     };
 
+    @undoBatch
+    @action
+    recurToggle = (childList: Doc[]) => {
+        if (childList.length > 0) {
+            childList.forEach(child => {
+                console.log(child);
+                child.runProcess = !!!child.runProcess;
+                child.toggleChildrenRun?.();
+            });
+        }
+    };
+
+    @undoBatch
+    @action
+    getRunningChildren = (childList: Doc[]) => {
+        if (childList.length === 0) {
+            return [];
+        }
+
+        const runningChildren = [];
+        childList.forEach(child => {
+            if (child.runProcess && child.getChildrenToRun) {
+                if (child.runProcess) {
+                    runningChildren.push(child);
+                }
+                runningChildren.push(...(child.getChildrenToRun?.() ?? []));
+            }
+        });
+        return runningChildren;
+    };
+
     constructor(props: any) {
         super(props);
         if (!TreeView._openLevelScript) {
@@ -235,6 +266,18 @@ export class TreeView extends React.Component<TreeViewProps> {
         }
         this._openScript = Doc.IsSystem(this.props.document) ? undefined : () => TreeView._openLevelScript!;
         this._editTitleScript = Doc.IsSystem(this.props.document) ? () => TreeView._openLevelScript! : () => TreeView._openTitleScript!;
+
+        // set for child processing highligting
+        // this.dataDoc.testing = 'testing';
+        this.dataDoc.hasChildren = this.childDocs.length > 0;
+        // this.dataDoc.children = this.childDocs;
+        this.dataDoc.toggleChildrenRun = () => {
+            this.recurToggle(this.childDocs);
+        };
+
+        this.dataDoc.getChildrenToRun = () => {
+            return this.getRunningChildren(this.childDocs);
+        };
     }
 
     _treeEle: any;
@@ -696,7 +739,11 @@ export class TreeView extends React.Component<TreeViewProps> {
                 ) : (
                     <div className="treeView-bulletIcons" style={{ color: Doc.IsSystem(DocCast(this.doc.proto)) ? 'red' : undefined }}>
                         <div className={`treeView-${this.onCheckedClick ? 'checkIcon' : 'expandIcon'}`}>
-                            <FontAwesomeIcon size="sm" icon={checked === 'check' ? 'check' : checked === 'x' ? 'times' : checked === 'unchecked' ? 'square' : !this.treeViewOpen ? 'caret-right' : 'caret-down'} />
+                            <FontAwesomeIcon
+                                size="sm"
+                                style={{ display: this.childDocs?.length >= 1 ? 'block' : 'none' }}
+                                icon={checked === 'check' ? 'check' : checked === 'x' ? 'times' : checked === 'unchecked' ? 'square' : !this.treeViewOpen ? 'caret-right' : 'caret-down'}
+                            />
                         </div>
                         {this.onCheckedClick ? null : typeof iconType === 'string' ? <FontAwesomeIcon icon={iconType as IconProp} /> : iconType}
                     </div>
@@ -899,7 +946,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                 })}
                 Document={this.doc}
                 fitWidth={returnTrue}
-                DataDoc={undefined}
+                DataDoc={this.dataDoc}
                 scriptContext={this}
                 hideDecorationTitle={this.props.treeView.outlineMode}
                 hideResizeHandles={this.props.treeView.outlineMode}
-- 
cgit v1.2.3-70-g09d2


From 9d6c7f8100de3a952d20ad41ab20872737cb909e Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sun, 27 Aug 2023 20:25:55 -0400
Subject: lots of cleanup to streamline import orderings (ie packages should
 not mutually import each other directly or via a chain).  change
 raiseWhenDragged to be keepZWhenDragged and got rid of system wide default.

---
 src/Utils.ts                                       |   2 +-
 src/client/DocServer.ts                            |  15 ++-
 src/client/apis/youtube/YoutubeBox.tsx             |   6 +-
 src/client/documents/Documents.ts                  |  10 +-
 src/client/util/CurrentUserUtils.ts                |  11 +-
 src/client/util/DictationManager.ts                |   2 +-
 src/client/util/DocumentManager.ts                 |  22 +++-
 src/client/util/DragManager.ts                     |  21 +---
 src/client/util/DropConverter.ts                   |  14 +--
 src/client/util/GroupManager.tsx                   |   4 +-
 src/client/util/GroupMemberView.tsx                |   2 +-
 src/client/util/SearchUtil.ts                      | 104 ++++++++++++++-
 src/client/util/SettingsManager.tsx                |  89 ++++++-------
 src/client/util/SharingManager.tsx                 |  10 +-
 src/client/util/reportManager/ReportManager.tsx    |   4 +-
 src/client/views/ContextMenuItem.tsx               |   6 +-
 src/client/views/DocumentDecorations.tsx           |  11 +-
 src/client/views/EditableView.tsx                  |   1 -
 src/client/views/FilterPanel.tsx                   |  23 ++--
 src/client/views/LightboxView.tsx                  |  11 +-
 src/client/views/Main.tsx                          |   6 +-
 src/client/views/MainView.tsx                      |  38 +++---
 src/client/views/PropertiesView.tsx                |  20 +--
 src/client/views/SidebarAnnos.tsx                  |   4 +-
 src/client/views/StyleProvider.tsx                 |  15 ++-
 src/client/views/UndoStack.tsx                     |   2 +-
 .../views/collections/CollectionDockingView.tsx    |   4 +-
 src/client/views/collections/CollectionMenu.tsx    |   2 +-
 .../collections/CollectionStackedTimeline.tsx      |   4 +-
 src/client/views/collections/TabDocView.tsx        |  13 +-
 src/client/views/collections/TreeSort.ts           |   6 +
 src/client/views/collections/TreeView.tsx          |  11 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  |   4 +-
 src/client/views/linking/LinkPopup.tsx             |   3 +-
 .../views/newlightbox/ButtonMenu/ButtonMenu.tsx    |  19 ++-
 src/client/views/newlightbox/NewLightboxView.tsx   | 139 ++++++++++-----------
 src/client/views/nodes/DocumentView.tsx            |  16 ++-
 src/client/views/nodes/FontIconBox/FontIconBox.tsx |  17 +--
 src/client/views/nodes/LinkDocPreview.tsx          |   6 +-
 src/client/views/nodes/LoadingBox.tsx              |   6 +-
 src/client/views/nodes/ScreenshotBox.tsx           |   6 +-
 src/client/views/nodes/VideoBox.tsx                |   5 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx |  24 ++--
 .../views/nodes/generativeFill/GenerativeFill.tsx  |  33 +++--
 src/client/views/nodes/trails/PresBox.tsx          |   4 +-
 src/client/views/pdf/AnchorMenu.tsx                |  15 +--
 src/client/views/search/IconBar.tsx                |  28 +++--
 src/client/views/search/SearchBox.tsx              | 110 +---------------
 src/client/views/topbar/TopBar.tsx                 |  16 ++-
 src/client/views/webcam/DashWebRTCVideo.tsx        |   6 +-
 src/fields/Doc.ts                                  |  26 +++-
 src/fields/RichTextUtils.ts                        |  10 +-
 52 files changed, 492 insertions(+), 494 deletions(-)
 create mode 100644 src/client/views/collections/TreeSort.ts

(limited to 'src/client/views/collections/TreeView.tsx')

diff --git a/src/Utils.ts b/src/Utils.ts
index 7f83ab8f5..9a94694a2 100644
--- a/src/Utils.ts
+++ b/src/Utils.ts
@@ -3,10 +3,10 @@ import v5 = require('uuid/v5');
 import { ColorState } from 'react-color';
 import * as rp from 'request-promise';
 import { Socket } from 'socket.io';
+import { DocumentType } from './client/documents/DocumentTypes';
 import { Colors } from './client/views/global/globalEnums';
 import { Message } from './server/Message';
 import Color = require('color');
-import { DocumentType } from './client/documents/DocumentTypes';
 
 export namespace Utils {
     export let CLICK_TIME = 300;
diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts
index 53c7b857a..5fdea131b 100644
--- a/src/client/DocServer.ts
+++ b/src/client/DocServer.ts
@@ -1,6 +1,5 @@
 import { runInAction } from 'mobx';
 import * as rp from 'request-promise';
-import * as io from 'socket.io-client';
 import { Doc, DocListCast, Opt } from '../fields/Doc';
 import { UpdatingFromServer } from '../fields/DocSymbols';
 import { FieldLoader } from '../fields/FieldLoader';
@@ -8,13 +7,13 @@ import { HandleUpdate, Id, Parent } from '../fields/FieldSymbols';
 import { ObjectField } from '../fields/ObjectField';
 import { RefField } from '../fields/RefField';
 import { DocCast, StrCast } from '../fields/Types';
-import MobileInkOverlay from '../mobile/MobileInkOverlay';
+//import MobileInkOverlay from '../mobile/MobileInkOverlay';
 import { emptyFunction, Utils } from '../Utils';
 import { GestureContent, MessageStore, MobileDocumentUploadContent, MobileInkOverlayContent, UpdateMobileInkOverlayPositionContent, YoutubeQueryTypes } from './../server/Message';
 import { DocumentType } from './documents/DocumentTypes';
 import { LinkManager } from './util/LinkManager';
 import { SerializationHelper } from './util/SerializationHelper';
-import { GestureOverlay } from './views/GestureOverlay';
+//import { GestureOverlay } from './views/GestureOverlay';
 
 /**
  * This class encapsulates the transfer and cross-client synchronization of
@@ -189,17 +188,17 @@ export namespace DocServer {
 
         // mobile ink overlay socket events to communicate between mobile view and desktop view
         _socket.addEventListener('receiveGesturePoints', (content: GestureContent) => {
-            MobileInkOverlay.Instance.drawStroke(content);
+            //   MobileInkOverlay.Instance.drawStroke(content);
         });
         _socket.addEventListener('receiveOverlayTrigger', (content: MobileInkOverlayContent) => {
-            GestureOverlay.Instance.enableMobileInkOverlay(content);
-            MobileInkOverlay.Instance.initMobileInkOverlay(content);
+            //GestureOverlay.Instance.enableMobileInkOverlay(content);
+            //    MobileInkOverlay.Instance.initMobileInkOverlay(content);
         });
         _socket.addEventListener('receiveUpdateOverlayPosition', (content: UpdateMobileInkOverlayPositionContent) => {
-            MobileInkOverlay.Instance.updatePosition(content);
+            //   MobileInkOverlay.Instance.updatePosition(content);
         });
         _socket.addEventListener('receiveMobileDocumentUpload', (content: MobileDocumentUploadContent) => {
-            MobileInkOverlay.Instance.uploadDocument(content);
+            //   MobileInkOverlay.Instance.uploadDocument(content);
         });
     }
 
diff --git a/src/client/apis/youtube/YoutubeBox.tsx b/src/client/apis/youtube/YoutubeBox.tsx
index 05879a247..2da9927c0 100644
--- a/src/client/apis/youtube/YoutubeBox.tsx
+++ b/src/client/apis/youtube/YoutubeBox.tsx
@@ -6,7 +6,7 @@ import { Cast, NumCast, StrCast } from '../../../fields/Types';
 import { Utils } from '../../../Utils';
 import { DocServer } from '../../DocServer';
 import { Docs } from '../../documents/Documents';
-import { DocumentDecorations } from '../../views/DocumentDecorations';
+import { DocumentView } from '../../views/nodes/DocumentView';
 import { FieldView, FieldViewProps } from '../../views/nodes/FieldView';
 import '../../views/nodes/WebBox.scss';
 import './YoutubeBox.scss';
@@ -355,9 +355,9 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
             </div>
         );
 
-        const frozen = !this.props.isSelected() || DocumentDecorations.Instance.Interacting;
+        const frozen = !this.props.isSelected() || DocumentView.Interacting;
 
-        const classname = 'webBox-cont' + (this.props.isSelected() && Doc.ActiveTool === InkTool.None && !DocumentDecorations.Instance.Interacting ? '-interactive' : '');
+        const classname = 'webBox-cont' + (this.props.isSelected() && Doc.ActiveTool === InkTool.None && !DocumentView.Interacting ? '-interactive' : '');
         return (
             <>
                 <div className={classname}>{content}</div>
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 1186446e1..919958b24 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -19,7 +19,6 @@ import { aggregateBounds, OmitKeys, Utils } from '../../Utils';
 import { YoutubeBox } from '../apis/youtube/YoutubeBox';
 import { DocServer } from '../DocServer';
 import { Networking } from '../Network';
-import { DocumentManager } from '../util/DocumentManager';
 import { DragManager, dropActionType } from '../util/DragManager';
 import { DirectoryImportBox } from '../util/Import & Export/DirectoryImportBox';
 import { FollowLinkScript } from '../util/LinkFollower';
@@ -34,12 +33,12 @@ import { ContextMenuProps } from '../views/ContextMenuItem';
 import { DFLT_IMAGE_NATIVE_DIM } from '../views/global/globalCssVariables.scss';
 import { ActiveArrowEnd, ActiveArrowStart, ActiveDash, ActiveFillColor, ActiveInkBezierApprox, ActiveInkColor, ActiveInkWidth, ActiveIsInkMask, InkingStroke } from '../views/InkingStroke';
 import { AudioBox } from '../views/nodes/AudioBox';
-import { FontIconBox } from '../views/nodes/FontIconBox/FontIconBox';
 import { ColorBox } from '../views/nodes/ColorBox';
 import { ComparisonBox } from '../views/nodes/ComparisonBox';
 import { DataVizBox } from '../views/nodes/DataVizBox/DataVizBox';
 import { EquationBox } from '../views/nodes/EquationBox';
 import { FieldViewProps } from '../views/nodes/FieldView';
+import { FontIconBox } from '../views/nodes/FontIconBox/FontIconBox';
 import { FormattedTextBox } from '../views/nodes/formattedText/FormattedTextBox';
 import { FunctionPlotBox } from '../views/nodes/FunctionPlotBox';
 import { ImageBox } from '../views/nodes/ImageBox';
@@ -394,7 +393,7 @@ export class DocumentOptions {
     onPointerUp?: ScriptField;
     _forceActive?: BOOLt = new BoolInfo('flag to handle pointer events when not selected (or otherwise active)');
     _dragOnlyWithinContainer?: BOOLt = new BoolInfo('whether the document should remain in its collection when someone tries to drag and drop it elsewhere');
-    _raiseWhenDragged?: BOOLt = new BoolInfo('whether a document is brought to front when dragged.');
+    _keepZWhenDragged?: BOOLt = new BoolInfo('whether a document should keep its z-order when dragged.');
     childDragAction?: DROPt = new DAInfo('what should happen to the child documents when they are dragged from the collection');
     dropConverter?: ScriptField; // script to run when documents are dropped on this Document.
     dropAction?: DROPt = new DAInfo("what should happen to this document when it's dropped somewhere else");
@@ -1371,7 +1370,7 @@ export namespace DocUtils {
     export let ActiveRecordings: { props: FieldViewProps; getAnchor: (addAsAnnotation: boolean) => Doc }[] = [];
 
     export function MakeLinkToActiveAudio(getSourceDoc: () => Doc | undefined, broadcastEvent = true) {
-        broadcastEvent && runInAction(() => (DocumentManager.Instance.RecordingEvent = DocumentManager.Instance.RecordingEvent + 1));
+        broadcastEvent && runInAction(() => (Doc.RecordingEvent = Doc.RecordingEvent + 1));
         return DocUtils.ActiveRecordings.map(audio => {
             const sourceDoc = getSourceDoc();
             return sourceDoc && DocUtils.MakeLink(sourceDoc, audio.getAnchor(true) || audio.props.Document, { link_displayLine: false, link_relationship: 'recording annotation:linked recording', link_description: 'recording timeline' });
@@ -1380,7 +1379,6 @@ export namespace DocUtils {
 
     export function MakeLink(source: Doc, target: Doc, linkSettings: { link_relationship?: string; link_description?: string; link_displayLine?: boolean }, id?: string, showPopup?: number[]) {
         if (!linkSettings.link_relationship) linkSettings.link_relationship = target.type === DocumentType.RTF ? 'Commentary:Comments On' : 'link';
-        const sv = DocumentManager.Instance.getDocumentView(source);
         if (target.doc === Doc.UserDoc()) return undefined;
 
         const makeLink = action((linkDoc: Doc, showPopup?: number[]) => {
@@ -1840,8 +1838,6 @@ export namespace DocUtils {
             }
             if (overwriteDoc) {
                 Doc.removeCurrentlyLoading(overwriteDoc);
-                // loading doc icons are just labels. so any icon views of loading docs need to be replaced with the proper icon view.
-                DocumentManager.Instance.getAllDocumentViews(overwriteDoc).forEach(dv => StrCast(dv.rootDoc.layout_fieldKey) === 'layout_icon' && dv.iconify(() => dv.iconify()));
             }
             generatedDocuments.push(doc);
         }
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index ea995e4af..d52e389d6 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -18,7 +18,6 @@ import { CollectionViewType, DocumentType } from "../documents/DocumentTypes";
 import { TreeViewType } from "../views/collections/CollectionTreeView";
 import { DashboardView } from "../views/DashboardView";
 import { Colors } from "../views/global/globalEnums";
-import { MainView } from "../views/MainView";
 import { OpenWhere } from "../views/nodes/DocumentView";
 import { ButtonType } from "../views/nodes/FontIconBox/FontIconBox";
 import { ImportElementBox } from "../views/nodes/importBox/ImportElementBox";
@@ -621,9 +620,9 @@ export class CurrentUserUtils {
 
     static freeTools(): Button[] {
         return [
-            { title: "Bottom",  icon: "arrows-down-to-line",toolTip: "Make doc topmost",                                   btnType: ButtonType.ClickButton,  expertMode: false, funcs: {}, scripts: { onClick: 'sendToBack()'}}, // Only when floating document is selected in freeform
-            { title: "Top",     icon: "arrows-up-to-line",  toolTip: "Make doc bottommost",                                btnType: ButtonType.ClickButton,  expertMode: false, funcs: {}, scripts: { onClick: 'bringToFront()'}}, // Only when floating document is selected in freeform
-            { title: "Z order", icon: "z",                  toolTip: "Bring Forward on Drag (double click to set for all)",waitForDoubleClickToClick:true, btnType: ButtonType.ToggleButton, expertMode: false, funcs: {}, scripts: { onClick: 'toggleRaiseOnDrag(false, _readOnly_)', onDoubleClick:`{ return toggleRaiseOnDrag(true, _readOnly_)`}}, // Only when floating document is selected in freeform
+            { title: "Bottom",  icon: "arrows-down-to-line",toolTip: "Make doc topmost",     btnType: ButtonType.ClickButton,  expertMode: false, funcs: {}, scripts: { onClick: 'sendToBack()'}}, // Only when floating document is selected in freeform
+            { title: "Top",     icon: "arrows-up-to-line",  toolTip: "Make doc bottommost",  btnType: ButtonType.ClickButton,  expertMode: false, funcs: {}, scripts: { onClick: 'bringToFront()'}}, // Only when floating document is selected in freeform
+            { title: "Z order", icon: "z",                  toolTip: "Keep Z order on Drag", btnType: ButtonType.ToggleButton, expertMode: false, funcs: {}, scripts: { onClick: '{ return toggleRaiseOnDrag(_readOnly_);}'}}, // Only when floating document is selected in freeform
         ]
     }
     static viewTools(): Button[] {
@@ -841,7 +840,6 @@ export class CurrentUserUtils {
         doc.isSystem ?? (doc.isSystem = true);
         doc.title ?? (doc.title = Doc.CurrentUserEmail);
         Doc.noviceMode ?? (Doc.noviceMode = true);
-        doc._raiseWhenDragged ?? (doc._raiseWhenDragged = true);
         doc._showLabel ?? (doc._showLabel = true);
         doc.textAlign ?? (doc.textAlign = "left");
         doc.activeTool = InkTool.None;
@@ -996,8 +994,5 @@ export class CurrentUserUtils {
 ScriptingGlobals.add(function MySharedDocs() { return Doc.MySharedDocs; }, "document containing all shared Docs");
 ScriptingGlobals.add(function IsNoviceMode() { return Doc.noviceMode; }, "is Dash in novice mode");
 ScriptingGlobals.add(function toggleComicMode() { Doc.UserDoc().renderStyle = Doc.UserDoc().renderStyle === "comic" ? undefined : "comic"; }, "switches between comic and normal document rendering");
-ScriptingGlobals.add(function createNewPresentation() { return MainView.Instance.createNewPresentation(); }, "creates a new presentation when called");
-ScriptingGlobals.add(function openPresentation(pres:Doc) { return MainView.Instance.openPresentation(pres); }, "creates a new presentation when called");
-ScriptingGlobals.add(function createNewFolder() { return MainView.Instance.createNewFolder(); }, "creates a new folder in myFiles when called");
 ScriptingGlobals.add(function importDocument() { return CurrentUserUtils.importDocument(); }, "imports files from device directly into the import sidebar");
 ScriptingGlobals.add(function setInkToolDefaults() { Doc.ActiveTool = InkTool.None; });
\ No newline at end of file
diff --git a/src/client/util/DictationManager.ts b/src/client/util/DictationManager.ts
index 717473aa1..0fd7e840c 100644
--- a/src/client/util/DictationManager.ts
+++ b/src/client/util/DictationManager.ts
@@ -11,7 +11,7 @@ import { Utils } from '../../Utils';
 import { Docs } from '../documents/Documents';
 import { DocumentType } from '../documents/DocumentTypes';
 import { DictationOverlay } from '../views/DictationOverlay';
-import { DocumentView, OpenWhere, OpenWhereMod } from '../views/nodes/DocumentView';
+import { DocumentView, OpenWhere } from '../views/nodes/DocumentView';
 import { SelectionManager } from './SelectionManager';
 import { UndoManager } from './UndoManager';
 
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 5b627c2f3..c2827dac7 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -1,4 +1,4 @@
-import { action, computed, observable, ObservableSet } from 'mobx';
+import { action, computed, observable, ObservableSet, observe, reaction } from 'mobx';
 import { Doc, DocListCast, Opt } from '../../fields/Doc';
 import { AclAdmin, AclEdit, Animation } from '../../fields/DocSymbols';
 import { Id } from '../../fields/FieldSymbols';
@@ -23,7 +23,6 @@ export class DocumentManager {
     //global holds all of the nodes (regardless of which collection they're in)
     @observable _documentViews = new Set<DocumentView>();
     @observable public LinkAnchorBoxViews: DocumentView[] = [];
-    @observable public RecordingEvent = 0;
     @observable public LinkedDocumentViews: { a: DocumentView; b: DocumentView; l: Doc }[] = [];
     @computed public get DocumentViews() {
         return Array.from(this._documentViews).filter(view => !(view.ComponentView instanceof KeyValueBox) && (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(view.docViewPath)));
@@ -41,7 +40,22 @@ export class DocumentManager {
     }
 
     //private constructor so no other class can create a nodemanager
-    private constructor() {}
+    private constructor() {
+        if (!Doc.CurrentlyLoading) Doc.CurrentlyLoading = [];
+        observe(Doc.CurrentlyLoading, change => {
+            // watch CurrentlyLoading-- when something is loaded, it's removed from the list and we have to update its icon if it were iconified since LoadingBox icons are different than the media they become
+            switch (change.type as any) {
+                case 'update':
+                    break;
+                case 'remove':
+                    // DocumentManager.Instance.getAllDocumentViews(change as any).forEach(dv => StrCast(dv.rootDoc.layout_fieldKey) === 'layout_icon' && dv.iconify(() => dv.iconify()));
+                    break;
+                case 'splice':
+                    (change as any).removed.forEach((doc: Doc) => DocumentManager.Instance.getAllDocumentViews(doc).forEach(dv => StrCast(dv.rootDoc.layout_fieldKey) === 'layout_icon' && dv.iconify(() => dv.iconify())));
+                    break;
+            }
+        });
+    }
 
     private _viewRenderedCbs: { doc: Doc; func: (dv: DocumentView) => any }[] = [];
     public AddViewRenderedCb = (doc: Opt<Doc>, func: (dv: DocumentView) => any) => {
@@ -310,7 +324,7 @@ export class DocumentManager {
         if (viewSpec && docView) {
             if (docView.ComponentView instanceof FormattedTextBox) docView.ComponentView?.focus(viewSpec, options);
             PresBox.restoreTargetDocView(docView, viewSpec, options.zoomTime ?? 500);
-            Doc.linkFollowHighlight(viewSpec ? [docView.rootDoc, viewSpec]: docView.rootDoc, undefined, options.effect);
+            Doc.linkFollowHighlight(viewSpec ? [docView.rootDoc, viewSpec] : docView.rootDoc, undefined, options.effect);
             if (options.playAudio) DocumentManager.playAudioAnno(docView.rootDoc);
             if (options.toggleTarget && (!options.didMove || docView.rootDoc.hidden)) docView.rootDoc.hidden = !docView.rootDoc.hidden;
             if (options.effect) docView.rootDoc[Animation] = options.effect;
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 489c9df4a..05da5ebed 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -61,12 +61,6 @@ export namespace DragManager {
     export let StartWindowDrag: Opt<(e: { pageX: number; pageY: number }, dragDocs: Doc[], finishDrag?: (aborted: boolean) => void) => void>;
     export let CompleteWindowDrag: Opt<(aborted: boolean) => void>;
 
-    export function GetRaiseWhenDragged() {
-        return BoolCast(Doc.UserDoc()._raiseWhenDragged);
-    }
-    export function SetRaiseWhenDragged(val: boolean) {
-        Doc.UserDoc()._raiseWhenDragged = val;
-    }
     export function Root() {
         const root = document.getElementById('root');
         if (!root) {
@@ -605,18 +599,9 @@ export namespace DragManager {
     }
 }
 
-ScriptingGlobals.add(function toggleRaiseOnDrag(forAllDocs: boolean, readOnly?: boolean) {
+ScriptingGlobals.add(function toggleRaiseOnDrag(readOnly?: boolean) {
     if (readOnly) {
-        if (SelectionManager.Views().length)
-            return SelectionManager.Views().some(dv => dv.rootDoc.raiseWhenDragged)
-                ? Colors.MEDIUM_BLUE
-                : SelectionManager.Views().some(dv => dv.rootDoc.raiseWhenDragged === false)
-                ? 'transparent'
-                : DragManager.GetRaiseWhenDragged()
-                ? Colors.MEDIUM_BLUE_ALT
-                : Colors.LIGHT_BLUE;
-        return DragManager.GetRaiseWhenDragged() ? Colors.MEDIUM_BLUE_ALT : 'transparent';
+        return SelectionManager.Views().some(dv => dv.rootDoc.keepZWhenDragged);
     }
-    if (!forAllDocs) SelectionManager.Views().map(dv => (dv.rootDoc.raiseWhenDragged ? (dv.rootDoc.raiseWhenDragged = undefined) : dv.rootDoc.raiseWhenDragged === false ? (dv.rootDoc.raiseWhenDragged = true) : (dv.rootDoc.raiseWhenDragged = false)));
-    else DragManager.SetRaiseWhenDragged(!DragManager.GetRaiseWhenDragged());
+    SelectionManager.Views().map(dv => (dv.rootDoc.keepZWhenDragged = !dv.rootDoc.keepZWhenDragged));
 });
diff --git a/src/client/util/DropConverter.ts b/src/client/util/DropConverter.ts
index f235be192..dbdf580cd 100644
--- a/src/client/util/DropConverter.ts
+++ b/src/client/util/DropConverter.ts
@@ -1,15 +1,15 @@
-import { DragManager } from './DragManager';
 import { Doc, DocListCast, Opt } from '../../fields/Doc';
-import { DocumentType } from '../documents/DocumentTypes';
 import { ObjectField } from '../../fields/ObjectField';
-import { StrCast, Cast } from '../../fields/Types';
-import { Docs } from '../documents/Documents';
-import { ScriptField, ComputedField } from '../../fields/ScriptField';
 import { RichTextField } from '../../fields/RichTextField';
-import { ImageField } from '../../fields/URLField';
-import { ScriptingGlobals } from './ScriptingGlobals';
 import { listSpec } from '../../fields/Schema';
+import { ScriptField } from '../../fields/ScriptField';
+import { Cast, StrCast } from '../../fields/Types';
+import { ImageField } from '../../fields/URLField';
+import { Docs } from '../documents/Documents';
+import { DocumentType } from '../documents/DocumentTypes';
 import { ButtonType } from '../views/nodes/FontIconBox/FontIconBox';
+import { DragManager } from './DragManager';
+import { ScriptingGlobals } from './ScriptingGlobals';
 
 export function MakeTemplate(doc: Doc, first: boolean = true, rename: Opt<string> = undefined, templateField: string = '') {
     if (templateField) Doc.GetProto(doc).title = templateField; /// the title determines which field is being templated
diff --git a/src/client/util/GroupManager.tsx b/src/client/util/GroupManager.tsx
index c79894032..8973306bf 100644
--- a/src/client/util/GroupManager.tsx
+++ b/src/client/util/GroupManager.tsx
@@ -282,7 +282,7 @@ export class GroupManager extends React.Component<{}> {
      */
     private get groupCreationModal() {
         const contents = (
-            <div className="group-create" style={{ background: SettingsManager.Instance.userBackgroundColor, color: SettingsManager.Instance.userColor }}>
+            <div className="group-create" style={{ background: SettingsManager.userBackgroundColor, color: SettingsManager.userColor }}>
                 <div className="group-heading" style={{ marginBottom: 0 }}>
                     <p>
                         <b>New Group</b>
@@ -367,7 +367,7 @@ export class GroupManager extends React.Component<{}> {
         const groups = this.groupSort === 'ascending' ? this.allGroups.sort(sortGroups) : this.groupSort === 'descending' ? this.allGroups.sort(sortGroups).reverse() : this.allGroups;
 
         return (
-            <div className="group-interface" style={{ background: SettingsManager.Instance.userBackgroundColor, color: SettingsManager.Instance.userColor }}>
+            <div className="group-interface" style={{ background: SettingsManager.userBackgroundColor, color: SettingsManager.userColor }}>
                 {this.groupCreationModal}
                 {this.currentGroup ? <GroupMemberView group={this.currentGroup} onCloseButtonClick={action(() => (this.currentGroup = undefined))} /> : null}
                 <div className="group-heading">
diff --git a/src/client/util/GroupMemberView.tsx b/src/client/util/GroupMemberView.tsx
index 535d8ccc2..7de0f336f 100644
--- a/src/client/util/GroupMemberView.tsx
+++ b/src/client/util/GroupMemberView.tsx
@@ -29,7 +29,7 @@ export class GroupMemberView extends React.Component<GroupMemberViewProps> {
         const hasEditAccess = GroupManager.Instance.hasEditAccess(this.props.group);
 
         return !this.props.group ? null : (
-            <div className="editing-interface" style={{ background: SettingsManager.Instance.userBackgroundColor, color: SettingsManager.Instance.userColor }}>
+            <div className="editing-interface" style={{ background: SettingsManager.userBackgroundColor, color: SettingsManager.userColor }}>
                 <div className="editing-header">
                     <input
                         className="group-title"
diff --git a/src/client/util/SearchUtil.ts b/src/client/util/SearchUtil.ts
index d154c48a4..64aa7ba9b 100644
--- a/src/client/util/SearchUtil.ts
+++ b/src/client/util/SearchUtil.ts
@@ -1,13 +1,115 @@
 import * as rp from 'request-promise';
 import { DocServer } from '../DocServer';
-import { Doc } from '../../fields/Doc';
+import { Doc, DocListCast, Field, Opt } from '../../fields/Doc';
 import { Id } from '../../fields/FieldSymbols';
 import { Utils } from '../../Utils';
 import { DocumentType } from '../documents/DocumentTypes';
+import { StrCast } from '../../fields/Types';
 
 export namespace SearchUtil {
     export type HighlightingResult = { [id: string]: { [key: string]: string[] } };
 
+    export function SearchCollection(rootDoc: Opt<Doc>, query: string) {
+        const blockedTypes = [DocumentType.PRESELEMENT, DocumentType.CONFIG, DocumentType.KVP, DocumentType.FONTICON, DocumentType.BUTTON, DocumentType.SCRIPTING];
+        const blockedKeys = [
+            'x',
+            'y',
+            'proto',
+            'width',
+            'layout_autoHeight',
+            'acl-Override',
+            'acl-Guest',
+            'embedContainer',
+            'zIndex',
+            'height',
+            'text_scrollHeight',
+            'text_height',
+            'cloneFieldFilter',
+            'isDataDoc',
+            'text_annotations',
+            'dragFactory_count',
+            'text_noTemplate',
+            'proto_embeddings',
+            'isSystem',
+            'layout_fieldKey',
+            'isBaseProto',
+            'xMargin',
+            'yMargin',
+            'links',
+            'layout',
+            'layout_keyValue',
+            'layout_fitWidth',
+            'type_collection',
+            'title_custom',
+            'freeform_panX',
+            'freeform_panY',
+            'freeform_scale',
+        ];
+        query = query.toLowerCase();
+
+        const results = new Map<Doc, string[]>();
+        if (rootDoc) {
+            const docs = DocListCast(rootDoc[Doc.LayoutFieldKey(rootDoc)]);
+            const docIDs: String[] = [];
+            SearchUtil.foreachRecursiveDoc(docs, (depth: number, doc: Doc) => {
+                const dtype = StrCast(doc.type) as DocumentType;
+                if (dtype && !blockedTypes.includes(dtype) && !docIDs.includes(doc[Id]) && depth >= 0) {
+                    const hlights = new Set<string>();
+                    SearchUtil.documentKeys(doc).forEach(
+                        key =>
+                            Field.toString(doc[key] as Field)
+                                .toLowerCase()
+                                .includes(query) && hlights.add(key)
+                    );
+                    blockedKeys.forEach(key => hlights.delete(key));
+
+                    if (Array.from(hlights.keys()).length > 0) {
+                        results.set(doc, Array.from(hlights.keys()));
+                    }
+                }
+                docIDs.push(doc[Id]);
+            });
+        }
+        return results;
+    }
+    /**
+     * @param {Doc} doc - doc for which keys are returned
+     *
+     * This method returns a list of a document doc's keys.
+     */
+    export function documentKeys(doc: Doc) {
+        const keys: { [key: string]: boolean } = {};
+        Doc.GetAllPrototypes(doc).map(proto => Object.keys(proto).forEach(key => (keys[key] = false)));
+        return Array.from(Object.keys(keys));
+    }
+
+    /**
+     * @param {Doc[]} docs - docs to be searched through recursively
+     * @param {number, Doc => void} func - function to be called on each doc
+     *
+     * This method iterates through an array of docs and all docs within those docs, calling
+     * the function func on each doc.
+     */
+    export function foreachRecursiveDoc(docs: Doc[], func: (depth: number, doc: Doc) => void) {
+        let newarray: Doc[] = [];
+        var depth = 0;
+        const visited: Doc[] = [];
+        while (docs.length > 0) {
+            newarray = [];
+            docs.filter(d => d && !visited.includes(d)).forEach(d => {
+                visited.push(d);
+                const fieldKey = Doc.LayoutFieldKey(d);
+                const annos = !Field.toString(Doc.LayoutField(d) as Field).includes('CollectionView');
+                const data = d[annos ? fieldKey + '_annotations' : fieldKey];
+                data && newarray.push(...DocListCast(data));
+                const sidebar = d[fieldKey + '_sidebar'];
+                sidebar && newarray.push(...DocListCast(sidebar));
+                func(depth, d);
+            });
+            docs = newarray;
+            depth++;
+        }
+    }
     export interface IdSearchResult {
         ids: string[];
         lines: string[][];
diff --git a/src/client/util/SettingsManager.tsx b/src/client/util/SettingsManager.tsx
index bb370e1a4..720badd40 100644
--- a/src/client/util/SettingsManager.tsx
+++ b/src/client/util/SettingsManager.tsx
@@ -13,7 +13,6 @@ import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager
 import { DocServer } from '../DocServer';
 import { Networking } from '../Network';
 import { MainViewModal } from '../views/MainViewModal';
-import { FontIconBox } from '../views/nodes/FontIconBox/FontIconBox';
 import { GroupManager } from './GroupManager';
 import './SettingsManager.scss';
 import { undoBatch } from './UndoManager';
@@ -67,15 +66,15 @@ export class SettingsManager extends React.Component<{}> {
         }
     };
 
-    @computed get userColor() {
+    @computed public static get userColor() {
         return StrCast(Doc.UserDoc().userColor);
     }
 
-    @computed get userVariantColor() {
+    @computed public static get userVariantColor() {
         return StrCast(Doc.UserDoc().userVariantColor);
     }
 
-    @computed get userBackgroundColor() {
+    @computed public static get userBackgroundColor() {
         return StrCast(Doc.UserDoc().userBackgroundColor);
     }
 
@@ -150,35 +149,35 @@ export class SettingsManager extends React.Component<{}> {
                         val: scheme,
                     }))}
                     dropdownType={DropdownType.SELECT}
-                    color={this.userColor}
+                    color={SettingsManager.userColor}
                     fillWidth
                 />
                 {userTheme === ColorScheme.Custom && (
                     <Group formLabel="Custom Theme">
                         <ColorPicker
                             tooltip={'User Color'} //
-                            color={this.userColor}
+                            color={SettingsManager.userColor}
                             type={Type.SEC}
                             icon={<FaFillDrip />}
-                            selectedColor={this.userColor}
+                            selectedColor={SettingsManager.userColor}
                             setSelectedColor={this.switchUserColor}
                             setFinalColor={this.switchUserColor}
                         />
                         <ColorPicker
                             tooltip={'User Background Color'}
-                            color={this.userColor}
+                            color={SettingsManager.userColor}
                             type={Type.SEC}
                             icon={<FaPalette />}
-                            selectedColor={this.userBackgroundColor}
+                            selectedColor={SettingsManager.userBackgroundColor}
                             setSelectedColor={this.switchUserBackgroundColor}
                             setFinalColor={this.switchUserBackgroundColor}
                         />
                         <ColorPicker
                             tooltip={'User Variant Color'}
-                            color={this.userColor}
+                            color={SettingsManager.userColor}
                             type={Type.SEC}
                             icon={<FaPalette />}
-                            selectedColor={this.userVariantColor}
+                            selectedColor={SettingsManager.userVariantColor}
                             setSelectedColor={this.switchUserVariantColor}
                             setFinalColor={this.switchUserVariantColor}
                         />
@@ -198,7 +197,7 @@ export class SettingsManager extends React.Component<{}> {
                     onClick={e => (Doc.UserDoc().layout_showTitle = Doc.UserDoc().layout_showTitle ? undefined : 'author_date')}
                     toggleStatus={Doc.UserDoc().layout_showTitle !== undefined}
                     size={Size.XSMALL}
-                    color={this.userColor}
+                    color={SettingsManager.userColor}
                 />
                 <Toggle
                     formLabel={'Show Full Toolbar'}
@@ -207,25 +206,25 @@ export class SettingsManager extends React.Component<{}> {
                     onClick={e => (Doc.UserDoc()['documentLinksButton-fullMenu'] = !Doc.UserDoc()['documentLinksButton-fullMenu'])}
                     toggleStatus={BoolCast(Doc.UserDoc()['documentLinksButton-fullMenu'])}
                     size={Size.XSMALL}
-                    color={this.userColor}
+                    color={SettingsManager.userColor}
                 />
                 <Toggle
                     formLabel={'Show Button Labels'}
                     formLabelPlacement={'right'}
                     toggleType={ToggleType.SWITCH}
-                    onClick={e => FontIconBox.SetShowLabels(!FontIconBox.GetShowLabels())}
-                    toggleStatus={FontIconBox.GetShowLabels()}
+                    onClick={e => Doc.SetShowIconLabels(!Doc.GetShowIconLabels())}
+                    toggleStatus={Doc.GetShowIconLabels()}
                     size={Size.XSMALL}
-                    color={this.userColor}
+                    color={SettingsManager.userColor}
                 />
                 <Toggle
                     formLabel={'Recognize Ink Gestures'}
                     formLabelPlacement={'right'}
                     toggleType={ToggleType.SWITCH}
-                    onClick={e => FontIconBox.SetRecognizeGestures(!FontIconBox.GetRecognizeGestures())}
-                    toggleStatus={FontIconBox.GetRecognizeGestures()}
+                    onClick={e => Doc.SetRecognizeGestures(!Doc.GetRecognizeGestures())}
+                    toggleStatus={Doc.GetRecognizeGestures()}
                     size={Size.XSMALL}
-                    color={this.userColor}
+                    color={SettingsManager.userColor}
                 />
                 <Toggle
                     formLabel={'Hide Labels In Ink Shapes'}
@@ -234,7 +233,7 @@ export class SettingsManager extends React.Component<{}> {
                     onClick={e => (Doc.UserDoc().activeInkHideTextLabels = !Doc.UserDoc().activeInkHideTextLabels)}
                     toggleStatus={BoolCast(Doc.UserDoc().activeInkHideTextLabels)}
                     size={Size.XSMALL}
-                    color={this.userColor}
+                    color={SettingsManager.userColor}
                 />
                 <Toggle
                     formLabel={'Open Ink Docs in Lightbox'}
@@ -243,7 +242,7 @@ export class SettingsManager extends React.Component<{}> {
                     onClick={e => (Doc.UserDoc().openInkInLightbox = !Doc.UserDoc().openInkInLightbox)}
                     toggleStatus={BoolCast(Doc.UserDoc().openInkInLightbox)}
                     size={Size.XSMALL}
-                    color={this.userColor}
+                    color={SettingsManager.userColor}
                 />
                 <Toggle
                     formLabel={'Show Link Lines'}
@@ -252,7 +251,7 @@ export class SettingsManager extends React.Component<{}> {
                     onClick={e => (Doc.UserDoc().showLinkLines = !Doc.UserDoc().showLinkLines)}
                     toggleStatus={BoolCast(Doc.UserDoc().showLinkLines)}
                     size={Size.XSMALL}
-                    color={this.userColor}
+                    color={SettingsManager.userColor}
                 />
             </div>
         );
@@ -284,7 +283,7 @@ export class SettingsManager extends React.Component<{}> {
                     <div className="tab-column-content">
                         {/* <NumberInput/> */}
                         <Group formLabel={'Default Font'}>
-                            <NumberDropdown color={this.userColor} numberDropdownType={'input'} min={0} max={50} step={2} type={Type.TERT} number={0} unit={'px'} setNumber={() => {}} />
+                            <NumberDropdown color={SettingsManager.userColor} numberDropdownType={'input'} min={0} max={50} step={2} type={Type.TERT} number={0} unit={'px'} setNumber={() => {}} />
                             <Dropdown
                                 items={fontFamilies.map(val => {
                                     return {
@@ -301,7 +300,7 @@ export class SettingsManager extends React.Component<{}> {
                                 setSelectedVal={val => {
                                     this.changeFontFamily(val as string);
                                 }}
-                                color={this.userColor}
+                                color={SettingsManager.userColor}
                                 fillWidth
                             />
                         </Group>
@@ -329,12 +328,12 @@ export class SettingsManager extends React.Component<{}> {
     @computed get passwordContent() {
         return (
             <div className="password-content">
-                <EditableText placeholder="Current password" type={Type.SEC} color={this.userColor} val={''} setVal={val => this.changeVal(val as string, 'curr')} fillWidth password />
-                <EditableText placeholder="New password" type={Type.SEC} color={this.userColor} val={''} setVal={val => this.changeVal(val as string, 'new')} fillWidth password />
-                <EditableText placeholder="Confirm new password" type={Type.SEC} color={this.userColor} val={''} setVal={val => this.changeVal(val as string, 'conf')} fillWidth password />
+                <EditableText placeholder="Current password" type={Type.SEC} color={SettingsManager.userColor} val={''} setVal={val => this.changeVal(val as string, 'curr')} fillWidth password />
+                <EditableText placeholder="New password" type={Type.SEC} color={SettingsManager.userColor} val={''} setVal={val => this.changeVal(val as string, 'new')} fillWidth password />
+                <EditableText placeholder="Confirm new password" type={Type.SEC} color={SettingsManager.userColor} val={''} setVal={val => this.changeVal(val as string, 'conf')} fillWidth password />
                 {!this.passwordResultText ? null : <div className={`${this.passwordResultText.startsWith('Error') ? 'error' : 'success'}-text`}>{this.passwordResultText}</div>}
-                <Button type={Type.SEC} text={'Forgot Password'} color={this.userColor} />
-                <Button type={Type.TERT} text={'Submit'} onClick={this.changePassword} color={this.userColor} />
+                <Button type={Type.SEC} text={'Forgot Password'} color={SettingsManager.userColor} />
+                <Button type={Type.TERT} text={'Submit'} onClick={this.changePassword} color={SettingsManager.userColor} />
             </div>
         );
     }
@@ -394,10 +393,10 @@ export class SettingsManager extends React.Component<{}> {
                             dropdownType={DropdownType.SELECT}
                             type={Type.TERT}
                             placement="bottom-start"
-                            color={this.userColor}
+                            color={SettingsManager.userColor}
                             fillWidth
                         />
-                        <Toggle formLabel={'Playground Mode'} toggleType={ToggleType.SWITCH} toggleStatus={this.playgroundMode} onClick={this.playgroundModeToggle} color={this.userColor} />
+                        <Toggle formLabel={'Playground Mode'} toggleType={ToggleType.SWITCH} toggleStatus={this.playgroundMode} onClick={this.playgroundModeToggle} color={SettingsManager.userColor} />
                     </div>
                     <div className="tab-column-title" style={{ marginTop: 20, marginBottom: 10 }}>
                         Freeform Navigation
@@ -422,15 +421,21 @@ export class SettingsManager extends React.Component<{}> {
                             dropdownType={DropdownType.SELECT}
                             type={Type.TERT}
                             placement="bottom-start"
-                            color={this.userColor}
+                            color={SettingsManager.userColor}
                         />
                     </div>
                 </div>
                 <div className="tab-column">
                     <div className="tab-column-title">Permissions</div>
                     <div className="tab-column-content">
-                        <Button text={'Manage Groups'} type={Type.TERT} onClick={() => GroupManager.Instance?.open()} color={this.userColor} />
-                        <Toggle toggleType={ToggleType.SWITCH} formLabel={'Default access private'} color={this.userColor} toggleStatus={BoolCast(Doc.defaultAclPrivate)} onClick={action(() => (Doc.defaultAclPrivate = !Doc.defaultAclPrivate))} />
+                        <Button text={'Manage Groups'} type={Type.TERT} onClick={() => GroupManager.Instance?.open()} color={SettingsManager.userColor} />
+                        <Toggle
+                            toggleType={ToggleType.SWITCH}
+                            formLabel={'Default access private'}
+                            color={SettingsManager.userColor}
+                            toggleStatus={BoolCast(Doc.defaultAclPrivate)}
+                            onClick={action(() => (Doc.defaultAclPrivate = !Doc.defaultAclPrivate))}
+                        />
                     </div>
                 </div>
             </div>
@@ -449,7 +454,7 @@ export class SettingsManager extends React.Component<{}> {
         ];
         return (
             <div className="settings-interface">
-                <div className="settings-panel" style={{ background: this.userColor }}>
+                <div className="settings-panel" style={{ background: SettingsManager.userColor }}>
                     <div className="settings-tabs">
                         {tabs.map(tab => {
                             const isActive = this.activeTab === tab.title;
@@ -457,8 +462,8 @@ export class SettingsManager extends React.Component<{}> {
                                 <div
                                     key={tab.title}
                                     style={{
-                                        background: isActive ? this.userBackgroundColor : this.userColor,
-                                        color: isActive ? this.userColor : this.userBackgroundColor,
+                                        background: isActive ? SettingsManager.userBackgroundColor : SettingsManager.userColor,
+                                        color: isActive ? SettingsManager.userColor : SettingsManager.userBackgroundColor,
                                     }}
                                     className={'tab-control ' + (isActive ? 'active' : 'inactive')}
                                     onClick={action(() => (this.activeTab = tab.title))}>
@@ -469,19 +474,19 @@ export class SettingsManager extends React.Component<{}> {
                     </div>
 
                     <div className="settings-user">
-                        <div style={{ color: this.userBackgroundColor }}>{DashVersion}</div>
-                        <div className="settings-username" style={{ color: this.userBackgroundColor }}>
+                        <div style={{ color: SettingsManager.userBackgroundColor }}>{DashVersion}</div>
+                        <div className="settings-username" style={{ color: SettingsManager.userBackgroundColor }}>
                             {Doc.CurrentUserEmail}
                         </div>
-                        <Button text={Doc.GuestDashboard ? 'Exit' : 'Log Out'} type={Type.TERT} color={this.userVariantColor} onClick={() => window.location.assign(Utils.prepend('/logout'))} />
+                        <Button text={Doc.GuestDashboard ? 'Exit' : 'Log Out'} type={Type.TERT} color={SettingsManager.userVariantColor} onClick={() => window.location.assign(Utils.prepend('/logout'))} />
                     </div>
                 </div>
 
                 <div className="close-button">
-                    <Button icon={<FontAwesomeIcon icon={'times'} size={'lg'} />} onClick={this.close} color={this.userColor} />
+                    <Button icon={<FontAwesomeIcon icon={'times'} size={'lg'} />} onClick={this.close} color={SettingsManager.userColor} />
                 </div>
 
-                <div className="settings-content" style={{ color: this.userColor, background: this.userBackgroundColor }}>
+                <div className="settings-content" style={{ color: SettingsManager.userColor, background: SettingsManager.userBackgroundColor }}>
                     {tabs.map(tab => (
                         <div key={tab.title} className={'tab-section ' + (this.activeTab === tab.title ? 'active' : 'inactive')}>
                             {tab.ele}
diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx
index 81ddeb9e3..9a9097bf7 100644
--- a/src/client/util/SharingManager.tsx
+++ b/src/client/util/SharingManager.tsx
@@ -18,10 +18,10 @@ import { DictationOverlay } from '../views/DictationOverlay';
 import { MainViewModal } from '../views/MainViewModal';
 import { DocumentView } from '../views/nodes/DocumentView';
 import { TaskCompletionBox } from '../views/nodes/TaskCompletedBox';
-import { SearchBox } from '../views/search/SearchBox';
 import { DocumentManager } from './DocumentManager';
 import { GroupManager, UserOptions } from './GroupManager';
 import { GroupMemberView } from './GroupMemberView';
+import { SearchUtil } from './SearchUtil';
 import { SelectionManager } from './SelectionManager';
 import { SettingsManager } from './SettingsManager';
 import './SharingManager.scss';
@@ -446,7 +446,7 @@ export class SharingManager extends React.Component<{}> {
 
         if (this.myDocAcls) {
             const newDocs: Doc[] = [];
-            SearchBox.foreachRecursiveDoc(docs, (depth, doc) => newDocs.push(doc));
+            SearchUtil.foreachRecursiveDoc(docs, (depth, doc) => newDocs.push(doc));
             docs = newDocs.filter(doc => GetEffectiveAcl(doc) === AclAdmin);
         }
 
@@ -527,10 +527,10 @@ export class SharingManager extends React.Component<{}> {
             const permissions = uniform ? StrCast(targetDoc?.[groupKey]) : '-multiple-';
 
             return !permissions ? null : (
-                <div key={groupKey} className={'container'} style={{ background: SettingsManager.Instance.userBackgroundColor, color: SettingsManager.Instance.userColor }}>
+                <div key={groupKey} className={'container'} style={{ background: SettingsManager.userBackgroundColor, color: SettingsManager.userColor }}>
                     <div className={'padding'}>{StrCast(group.title)}</div>
                     &nbsp;
-                    {group instanceof Doc ? <IconButton icon={<FontAwesomeIcon icon={'info-circle'} />} size={Size.XSMALL} color={SettingsManager.Instance.userColor} onClick={action(() => (GroupManager.Instance.currentGroup = group))} /> : null}
+                    {group instanceof Doc ? <IconButton icon={<FontAwesomeIcon icon={'info-circle'} />} size={Size.XSMALL} color={SettingsManager.userColor} onClick={action(() => (GroupManager.Instance.currentGroup = group))} /> : null}
                     <div className={'edit-actions'}>
                         {admin || this.myDocAcls ? (
                             <select className={`permissions-dropdown-${permissions}`} value={permissions} onChange={e => this.setInternalGroupSharing(group, e.currentTarget.value)}>
@@ -552,7 +552,7 @@ export class SharingManager extends React.Component<{}> {
                 <div
                     className="sharing-contents"
                     style={{
-                        background: SettingsManager.Instance.userBackgroundColor,
+                        background: SettingsManager.userBackgroundColor,
                         color: StrCast(Doc.UserDoc().userColor),
                     }}>
                     <p className="share-title" style={{ color: StrCast(Doc.UserDoc().userColor) }}>
diff --git a/src/client/util/reportManager/ReportManager.tsx b/src/client/util/reportManager/ReportManager.tsx
index 3cd2d47a0..6a236face 100644
--- a/src/client/util/reportManager/ReportManager.tsx
+++ b/src/client/util/reportManager/ReportManager.tsx
@@ -211,11 +211,11 @@ export class ReportManager extends React.Component<{}> {
      * @returns the component that dispays all issues
      */
     private viewIssuesComponent = () => {
-        const darkMode = isDarkMode(SettingsManager.Instance.userBackgroundColor);
+        const darkMode = isDarkMode(SettingsManager.userBackgroundColor);
         const colors = darkMode ? darkColors : lightColors;
 
         return (
-            <div className="view-issues" style={{ backgroundColor: SettingsManager.Instance.userBackgroundColor, color: colors.text }}>
+            <div className="view-issues" style={{ backgroundColor: SettingsManager.userBackgroundColor, color: colors.text }}>
                 <div className="left" style={{ display: this.rightExpanded ? 'none' : 'flex' }}>
                     <div className="report-header">
                         <h2 style={{ color: colors.text }}>Open Issues</h2>
diff --git a/src/client/views/ContextMenuItem.tsx b/src/client/views/ContextMenuItem.tsx
index b53379435..c2cbca3e1 100644
--- a/src/client/views/ContextMenuItem.tsx
+++ b/src/client/views/ContextMenuItem.tsx
@@ -96,7 +96,7 @@ export class ContextMenuItem extends React.Component<ContextMenuProps & { select
                     <div
                         className={`contextMenu-item-background`}
                         style={{
-                            background: SettingsManager.Instance.userColor,
+                            background: SettingsManager.userColor,
                         }}
                     />
                 </div>
@@ -112,7 +112,7 @@ export class ContextMenuItem extends React.Component<ContextMenuProps & { select
                     style={{
                         marginLeft: window.innerHeight - this._overPosX - 50 > 0 ? '90%' : '20%',
                         marginTop,
-                        background: SettingsManager.Instance.userBackgroundColor,
+                        background: SettingsManager.userBackgroundColor,
                     }}>
                     {this._items.map(prop => (
                         <ContextMenuItem {...prop} key={prop.description} closeMenu={this.props.closeMenu} />
@@ -146,7 +146,7 @@ export class ContextMenuItem extends React.Component<ContextMenuProps & { select
                     <div
                         className={`contextMenu-item-background`}
                         style={{
-                            background: SettingsManager.Instance.userColor,
+                            background: SettingsManager.userColor,
                         }}
                     />
                     {submenu}
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 90425f264..3018dad79 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -57,7 +57,6 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
     @observable private _editingTitle = false;
     @observable private _hidden = false;
     @observable public AddToSelection = false; // if Shift is pressed, then this should be set so that clicking on the selection background is ignored so overlapped documents can be added to the selection set.
-    @observable public Interacting = false;
     @observable public pushIcon: IconProp = 'arrow-alt-circle-up';
     @observable public pullIcon: IconProp = 'arrow-alt-circle-down';
     @observable public pullColor: string = 'white';
@@ -330,7 +329,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
      */
     @action
     onRadiusDown = (e: React.PointerEvent): void => {
-        this._isRounding = DocumentDecorations.Instance.Interacting = true;
+        this._isRounding = DocumentView.Interacting = true;
         this._resizeUndo = UndoManager.StartBatch('DocDecs set radius');
         // Call util move event function
         setupMoveUpEvents(
@@ -353,7 +352,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
                 return false;
             }, // moveEvent
             action(e => {
-                DocumentDecorations.Instance.Interacting = this._isRounding = false;
+                DocumentView.Interacting = this._isRounding = false;
                 this._resizeUndo?.end();
             }), // upEvent
             e => {}, // clickEvent,
@@ -478,7 +477,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
     @action
     onPointerDown = (e: React.PointerEvent): void => {
         setupMoveUpEvents(this, e, this.onPointerMove, this.onPointerUp, emptyFunction);
-        this.Interacting = true; // turns off pointer events on things like youtube videos and web pages so that dragging doesn't get "stuck" when cursor moves over them
+        DocumentView.Interacting = true; // turns off pointer events on things like youtube videos and web pages so that dragging doesn't get "stuck" when cursor moves over them
         this._resizeHdlId = e.currentTarget.className;
         const bounds = e.currentTarget.getBoundingClientRect();
         this._offX = this._resizeHdlId.toLowerCase().includes('left') ? bounds.right - e.clientX : bounds.left - e.clientX;
@@ -688,7 +687,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
     @action
     onPointerUp = (e: PointerEvent): void => {
         this._resizeHdlId = '';
-        this.Interacting = false;
+        DocumentView.Interacting = false;
         this._resizeUndo?.end();
         SnappingManager.clearSnapLines();
 
@@ -895,7 +894,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
                         height: bounds.b - bounds.y + this._resizeBorderWidth + 'px',
                         left: bounds.x - this._resizeBorderWidth / 2,
                         top: bounds.y - this._resizeBorderWidth / 2,
-                        pointerEvents: DocumentDecorations.Instance.AddToSelection || this.Interacting ? 'none' : 'all',
+                        pointerEvents: DocumentDecorations.Instance.AddToSelection || DocumentView.Interacting ? 'none' : 'all',
                         display: SelectionManager.Views().length <= 1 || hideDecorations ? 'none' : undefined,
                     }}
                     onPointerDown={this.onBackgroundDown}
diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx
index d60617020..147921596 100644
--- a/src/client/views/EditableView.tsx
+++ b/src/client/views/EditableView.tsx
@@ -6,7 +6,6 @@ import { ObjectField } from '../../fields/ObjectField';
 import './EditableView.scss';
 import { DocumentIconContainer } from './nodes/DocumentIcon';
 import { OverlayView } from './OverlayView';
-import { EditableText } from 'browndash-components';
 
 export interface EditableProps {
     /**
diff --git a/src/client/views/FilterPanel.tsx b/src/client/views/FilterPanel.tsx
index 11c2fc86c..b61ff35c7 100644
--- a/src/client/views/FilterPanel.tsx
+++ b/src/client/views/FilterPanel.tsx
@@ -1,23 +1,20 @@
 import React = require('react');
 import { action, computed, observable, ObservableMap } from 'mobx';
 import { observer } from 'mobx-react';
+import { Handles, Rail, Slider, Ticks, Tracks } from 'react-compound-slider';
+import { AiOutlineMinusSquare, AiOutlinePlusSquare } from 'react-icons/ai';
+import { CiCircleRemove } from 'react-icons/ci';
 import Select from 'react-select';
-import { Checkbox, Tooltip } from '@material-ui/core';
 import { Doc, DocListCast, Field, StrListCast } from '../../fields/Doc';
 import { RichTextField } from '../../fields/RichTextField';
-import { StrCast } from '../../fields/Types';
+import { DocumentOptions, FInfo } from '../documents/Documents';
 import { DocumentManager } from '../util/DocumentManager';
 import { UserOptions } from '../util/GroupManager';
+import { SearchUtil } from '../util/SearchUtil';
+import { undoable } from '../util/UndoManager';
 import './FilterPanel.scss';
 import { FieldView } from './nodes/FieldView';
-import { SearchBox } from './search/SearchBox';
-import { undoable } from '../util/UndoManager';
-import { AiOutlineMinusSquare, AiOutlinePlusSquare } from 'react-icons/ai';
-import { CiCircleRemove } from 'react-icons/ci';
-import { Slider, Rail, Handles, Tracks, Ticks } from 'react-compound-slider';
-import { TooltipRail, Handle, Tick, Track } from './nodes/SliderBox-components';
-import { DocumentOptions, FInfo } from '../documents/Documents';
-import { string32 } from 'pdfjs-dist/types/src/shared/util';
+import { Handle, Tick, TooltipRail, Track } from './nodes/SliderBox-components';
 
 interface filterProps {
     rootDoc: Doc;
@@ -49,7 +46,7 @@ export class FilterPanel extends React.Component<filterProps> {
         const allDocs = new Set<Doc>();
         const targetDoc = this.targetDoc;
         if (targetDoc) {
-            SearchBox.foreachRecursiveDoc([this.targetDoc], (depth, doc) => allDocs.add(doc));
+            SearchUtil.foreachRecursiveDoc([this.targetDoc], (depth, doc) => allDocs.add(doc));
         }
         console.log('this is all Docs' + Array.from(allDocs));
         return Array.from(allDocs);
@@ -62,7 +59,7 @@ export class FilterPanel extends React.Component<filterProps> {
         const noviceFields = [...noviceReqFields, ...noviceLayoutFields];
 
         const keys = new Set<string>(noviceFields);
-        this.allDocs.forEach(doc => SearchBox.documentKeys(doc).filter(key => keys.add(key)));
+        this.allDocs.forEach(doc => SearchUtil.documentKeys(doc).filter(key => keys.add(key)));
         const sortedKeys = Array.from(keys.keys())
             .filter(key => key[0])
             .filter(key => key.indexOf('modificationDate') !== -1 || (key[0] === key[0].toUpperCase() && !key.startsWith('_')) || noviceFields.includes(key) || !Doc.noviceMode)
@@ -236,7 +233,7 @@ export class FilterPanel extends React.Component<filterProps> {
 
     facetValues = (facetHeader: string) => {
         const allCollectionDocs = new Set<Doc>();
-        SearchBox.foreachRecursiveDoc(this.targetDocChildren, (depth: number, doc: Doc) => allCollectionDocs.add(doc));
+        SearchUtil.foreachRecursiveDoc(this.targetDocChildren, (depth: number, doc: Doc) => allCollectionDocs.add(doc));
         const set = new Set<string>([String.fromCharCode(127) + '--undefined--']);
         if (facetHeader === 'tags')
             allCollectionDocs.forEach(child =>
diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx
index afb76b9ac..8f081b321 100644
--- a/src/client/views/LightboxView.tsx
+++ b/src/client/views/LightboxView.tsx
@@ -16,7 +16,6 @@ import { CollectionStackedTimeline } from './collections/CollectionStackedTimeli
 import { TabDocView } from './collections/TabDocView';
 import { GestureOverlay } from './GestureOverlay';
 import './LightboxView.scss';
-import { MainView } from './MainView';
 import { DocumentView, OpenWhere, OpenWhereMod } from './nodes/DocumentView';
 import { DefaultStyleProvider, wavyBorderPath } from './StyleProvider';
 
@@ -61,7 +60,7 @@ export class LightboxView extends React.Component<LightboxViewProps> {
             this._childFilters && (this._childFilters.length = 0);
             this._future = this._history = [];
             Doc.ActiveTool = InkTool.None;
-            MainView.Instance._exploreMode = false;
+            DocumentView.ExploreMode = false;
         } else {
             const l = DocUtils.MakeLinkToActiveAudio(() => doc).lastElement();
             l && (Cast(l.link_anchor_2, Doc, null).backgroundColor = 'lightgreen');
@@ -270,7 +269,7 @@ export class LightboxView extends React.Component<LightboxViewProps> {
                             addDocTab={this.addDocTab}
                             pinToPres={TabDocView.PinDoc}
                             bringToFront={emptyFunction}
-                            onBrowseClick={MainView.Instance.exploreMode}
+                            onBrowseClick={DocumentView.exploreMode}
                             focus={emptyFunction}
                         />
                     </GestureOverlay>
@@ -335,12 +334,12 @@ export class LightboxView extends React.Component<LightboxViewProps> {
                 <div
                     className="lightboxView-exploreBtn"
                     title="toggle explore mode to navigate among documents only"
-                    style={{ background: MainView.Instance._exploreMode ? 'white' : undefined }}
+                    style={{ background: DocumentView.ExploreMode ? 'white' : undefined }}
                     onClick={action(e => {
                         e.stopPropagation();
-                        MainView.Instance._exploreMode = !MainView.Instance._exploreMode;
+                        DocumentView.ExploreMode = !DocumentView.ExploreMode;
                     })}>
-                    <FontAwesomeIcon color={MainView.Instance._exploreMode ? 'black' : 'white'} icon={'globe-americas'} size="2x" />
+                    <FontAwesomeIcon color={DocumentView.ExploreMode ? 'black' : 'white'} icon={'globe-americas'} size="2x" />
                 </div>
             </div>
         );
diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx
index 6dd1d53ee..a04309d0c 100644
--- a/src/client/views/Main.tsx
+++ b/src/client/views/Main.tsx
@@ -2,18 +2,18 @@
 //     (module as any).hot.accept();
 // }
 
+import * as dotenv from 'dotenv'; // see https://github.com/motdotla/dotenv#how-do-i-use-dotenv-with-import
 import * as React from 'react';
 import * as ReactDOM from 'react-dom/client';
 import { AssignAllExtensions } from '../../extensions/General/Extensions';
 import { FieldLoader } from '../../fields/FieldLoader';
 import { CurrentUserUtils } from '../util/CurrentUserUtils';
+import { PingManager } from '../util/PingManager';
 import { ReplayMovements } from '../util/ReplayMovements';
 import { TrackMovements } from '../util/TrackMovements';
 import { CollectionView } from './collections/CollectionView';
-import { MainView } from './MainView';
-import * as dotenv from 'dotenv'; // see https://github.com/motdotla/dotenv#how-do-i-use-dotenv-with-import
-import { PingManager } from '../util/PingManager';
 import './global/globalScripts';
+import { MainView } from './MainView';
 dotenv.config();
 
 AssignAllExtensions();
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 6a743a5e6..dde04dcc0 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -9,7 +9,6 @@ import { observer } from 'mobx-react';
 import 'normalize.css';
 import * as React from 'react';
 import { Doc, DocListCast, Opt } from '../../fields/Doc';
-import { ScriptField } from '../../fields/ScriptField';
 import { DocCast, StrCast } from '../../fields/Types';
 import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, returnZero, setupMoveUpEvents, Utils } from '../../Utils';
 import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager';
@@ -77,7 +76,6 @@ export class MainView extends React.Component {
     public static Live: boolean = false;
     private _docBtnRef = React.createRef<HTMLDivElement>();
 
-    @observable public LastButton: Opt<Doc>;
     @observable private _windowWidth: number = 0;
     @observable private _windowHeight: number = 0;
     @observable private _dashUIWidth: number = 0; // width of entire main dashboard region including left menu buttons and properties panel (but not including the dashboard selector button row)
@@ -529,7 +527,6 @@ export class MainView extends React.Component {
         window.addEventListener('beforeunload', DocServer.UPDATE_SERVER_CACHE);
         window.addEventListener('drop', e => e.preventDefault(), false); // prevent default behavior of navigating to a new web page
         window.addEventListener('dragover', e => e.preventDefault(), false);
-        // document.addEventListener("pointermove", action(e => SearchBox.Instance._undoBackground = UndoManager.batchCounter ? "#000000a8" : undefined));
         document.addEventListener('pointerdown', this.globalPointerDown, true);
         document.addEventListener('pointermove', this.globalPointerMove, true);
         document.addEventListener('pointerup', this.globalPointerClick, true);
@@ -572,11 +569,7 @@ export class MainView extends React.Component {
         Doc.AddDocToList(Doc.MyFilesystem, 'data', folder);
     };
 
-    @observable _exploreMode = false;
-    @computed get exploreMode() {
-        return () => (this._exploreMode ? ScriptField.MakeScript('CollectionBrowseClick(documentView, clientX, clientY)', { documentView: 'any', clientX: 'number', clientY: 'number' })! : undefined);
-    }
-    waitForDoubleClick = () => (this._exploreMode ? 'never' : undefined);
+    waitForDoubleClick = () => (DocumentView.ExploreMode ? 'never' : undefined);
     headerBarScreenXf = () => new Transform(-this.leftScreenOffsetOfMainDocView - this.leftMenuFlyoutWidth(), -this.headerBarDocHeight(), 1);
     mainScreenToLocalXf = () => new Transform(-this.leftScreenOffsetOfMainDocView - this.leftMenuFlyoutWidth(), -this.topOfMainDocContent, 1);
     addHeaderDoc = (doc: Doc | Doc[], annotationKey?: string) => (doc instanceof Doc ? [doc] : doc).reduce((done, doc) => Doc.AddDocToList(this.headerBarDoc, 'data', doc), true);
@@ -747,7 +740,7 @@ export class MainView extends React.Component {
 
     @computed get leftMenuPanel() {
         return (
-            <div key="menu" className="mainView-leftMenuPanel" style={{ background: StrCast(Doc.UserDoc().userBackgroundColor), display: LightboxView.LightboxDoc ? 'none' : undefined }}>
+            <div key="menu" className="mainView-leftMenuPanel" style={{ background: SettingsManager.userBackgroundColor, display: LightboxView.LightboxDoc ? 'none' : undefined }}>
                 <DocumentView
                     Document={Doc.MyLeftSidebarMenu}
                     DataDoc={undefined}
@@ -804,16 +797,16 @@ export class MainView extends React.Component {
                     {this.flyout}
                     <div
                         className="mainView-libraryHandle"
-                        style={{ background: StrCast(Doc.UserDoc().userBackgroundColor), left: leftMenuFlyoutWidth - 10 /* ~half width of handle */, display: !this._leftMenuFlyoutWidth ? 'none' : undefined }}
+                        style={{ background: SettingsManager.userBackgroundColor, left: leftMenuFlyoutWidth - 10 /* ~half width of handle */, display: !this._leftMenuFlyoutWidth ? 'none' : undefined }}
                         onPointerDown={this.onFlyoutPointerDown}>
-                        <FontAwesomeIcon icon="chevron-left" color={StrCast(Doc.UserDoc().userColor)} style={{ opacity: '50%' }} size="sm" />
+                        <FontAwesomeIcon icon="chevron-left" color={SettingsManager.userColor} style={{ opacity: '50%' }} size="sm" />
                     </div>
                     <div className="mainView-innerContainer" style={{ width: `calc(100% - ${width}px)` }}>
                         {this.dockingContent}
 
                         {this._hideUI ? null : (
-                            <div className="mainView-propertiesDragger" key="props" onPointerDown={this.onPropertiesPointerDown} style={{ background: StrCast(Doc.UserDoc().userBackgroundColor), right: this.propertiesWidth() - 1 }}>
-                                <FontAwesomeIcon icon={this.propertiesWidth() < 10 ? 'chevron-left' : 'chevron-right'} color={StrCast(Doc.UserDoc().userColor)} size="sm" />
+                            <div className="mainView-propertiesDragger" key="props" onPointerDown={this.onPropertiesPointerDown} style={{ background: SettingsManager.userBackgroundColor, right: this.propertiesWidth() - 1 }}>
+                                <FontAwesomeIcon icon={this.propertiesWidth() < 10 ? 'chevron-left' : 'chevron-right'} color={SettingsManager.userColor} size="sm" />
                             </div>
                         )}
                         <div className="properties-container" style={{ width: this.propertiesWidth() }}>
@@ -857,11 +850,11 @@ export class MainView extends React.Component {
         //setTimeout(action(() => (this._leftMenuFlyoutWidth += 0.5)));
 
         this._sidebarContent.proto = DocCast(button.target);
-        this.LastButton = button;
+        DocumentView.LastPressedSidebarBtn = button;
     });
 
     closeFlyout = action(() => {
-        this.LastButton = undefined;
+        DocumentView.LastPressedSidebarBtn = undefined;
         this._panelContent = 'none';
         this._sidebarContent.proto = undefined;
         this._leftMenuFlyoutWidth = 0;
@@ -879,7 +872,7 @@ export class MainView extends React.Component {
 
     @computed get docButtons() {
         return !Doc.MyDockedBtns ? null : (
-            <div className="mainView-docButtons" style={{ background: StrCast(Doc.UserDoc().userBackgroundColor), color: StrCast(Doc.UserDoc().userColor) }} ref={this._docBtnRef}>
+            <div className="mainView-docButtons" style={{ background: SettingsManager.userBackgroundColor, color: SettingsManager.userColor }} ref={this._docBtnRef}>
                 <CollectionLinearView
                     Document={Doc.MyDockedBtns}
                     DataDoc={undefined}
@@ -998,8 +991,8 @@ export class MainView extends React.Component {
             <div
                 className={`mainView-container ${this.colorScheme}`}
                 style={{
-                    color: StrCast(Doc.UserDoc().userColor),
-                    background: StrCast(Doc.UserDoc().userBackgroundColor),
+                    color: SettingsManager.userColor,
+                    background: SettingsManager.userBackgroundColor,
                 }}
                 onScroll={() => (ele => (ele.scrollTop = ele.scrollLeft = 0))(document.getElementById('root')!)}
                 ref={r => {
@@ -1068,3 +1061,12 @@ export class MainView extends React.Component {
 ScriptingGlobals.add(function selectMainMenu(doc: Doc, title: string) {
     MainView.Instance.selectMenu(doc);
 });
+ScriptingGlobals.add(function createNewPresentation() {
+    return MainView.Instance.createNewPresentation();
+}, 'creates a new presentation when called');
+ScriptingGlobals.add(function openPresentation(pres: Doc) {
+    return MainView.Instance.openPresentation(pres);
+}, 'creates a new presentation when called');
+ScriptingGlobals.add(function createNewFolder() {
+    return MainView.Instance.createNewFolder();
+}, 'creates a new folder in myFiles when called');
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 4fe6847c3..83bd1b860 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -188,7 +188,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
             });
 
             rows.push(
-                <div className="propertiesView-field" key="newKeyValue" style={{ marginTop: '3px', backgroundColor: SettingsManager.Instance.userBackgroundColor, textAlign: 'center' }}>
+                <div className="propertiesView-field" key="newKeyValue" style={{ marginTop: '3px', backgroundColor: SettingsManager.userBackgroundColor, textAlign: 'center' }}>
                     <EditableView key="editableView" oneLine contents={'add key:value or #tags'} height={13} fontSize={10} GetValue={() => ''} SetValue={this.setKeyValue} />
                 </div>
             );
@@ -1664,7 +1664,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                             <div className="propertiesView-title" style={{ width: this.props.width }}>
                                 Properties
                                 <div className="propertiesView-info" onClick={() => window.open('https://brown-dash.github.io/Dash-Documentation/properties')}>
-                                    <IconButton icon={<FontAwesomeIcon icon="info-circle" />} color={SettingsManager.Instance.userColor} />
+                                    <IconButton icon={<FontAwesomeIcon icon="info-circle" />} color={SettingsManager.userColor} />
                                 </div>
                             </div>
                         </div>
@@ -1706,8 +1706,8 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                                     className="propertiesView-presentationTrails-title"
                                     onPointerDown={action(() => (this.openPresTransitions = !this.openPresTransitions))}
                                     style={{
-                                        color: SettingsManager.Instance.userColor,
-                                        backgroundColor: this.openPresTransitions ? SettingsManager.Instance.userVariantColor : SettingsManager.Instance.userBackgroundColor,
+                                        color: SettingsManager.userColor,
+                                        backgroundColor: this.openPresTransitions ? SettingsManager.userVariantColor : SettingsManager.userBackgroundColor,
                                     }}>
                                     &nbsp; <FontAwesomeIcon style={{ alignSelf: 'center' }} icon={'rocket'} /> &nbsp; Transitions
                                     <div className="propertiesView-presentationTrails-title-icon">
@@ -1723,8 +1723,8 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                                     className="propertiesView-presentationTrails-title"
                                     onPointerDown={action(() => (this.openPresVisibilityAndDuration = !this.openPresVisibilityAndDuration))}
                                     style={{
-                                        color: SettingsManager.Instance.userColor,
-                                        backgroundColor: this.openPresVisibilityAndDuration ? SettingsManager.Instance.userVariantColor : SettingsManager.Instance.userBackgroundColor,
+                                        color: SettingsManager.userColor,
+                                        backgroundColor: this.openPresVisibilityAndDuration ? SettingsManager.userVariantColor : SettingsManager.userBackgroundColor,
                                     }}>
                                     &nbsp; <FontAwesomeIcon style={{ alignSelf: 'center' }} icon={'rocket'} /> &nbsp; Visibilty
                                     <div className="propertiesView-presentationTrails-title-icon">
@@ -1740,8 +1740,8 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                                     className="propertiesView-presentationTrails-title"
                                     onPointerDown={action(() => (this.openPresProgressivize = !this.openPresProgressivize))}
                                     style={{
-                                        color: SettingsManager.Instance.userColor,
-                                        backgroundColor: this.openPresProgressivize ? SettingsManager.Instance.userVariantColor : SettingsManager.Instance.userBackgroundColor,
+                                        color: SettingsManager.userColor,
+                                        backgroundColor: this.openPresProgressivize ? SettingsManager.userVariantColor : SettingsManager.userBackgroundColor,
                                     }}>
                                     &nbsp; <FontAwesomeIcon style={{ alignSelf: 'center' }} icon={'rocket'} /> &nbsp; Progressivize
                                     <div className="propertiesView-presentationTrails-title-icon">
@@ -1757,8 +1757,8 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                                     className="propertiesView-presentationTrails-title"
                                     onPointerDown={action(() => (this.openSlideOptions = !this.openSlideOptions))}
                                     style={{
-                                        color: SettingsManager.Instance.userColor,
-                                        backgroundColor: this.openSlideOptions ? SettingsManager.Instance.userVariantColor : SettingsManager.Instance.userBackgroundColor,
+                                        color: SettingsManager.userColor,
+                                        backgroundColor: this.openSlideOptions ? SettingsManager.userVariantColor : SettingsManager.userBackgroundColor,
                                     }}>
                                     &nbsp; <FontAwesomeIcon style={{ alignSelf: 'center' }} icon={type === DocumentType.AUDIO ? 'file-audio' : 'file-video'} /> &nbsp; {type === DocumentType.AUDIO ? 'Audio Options' : 'Video Options'}
                                     <div className="propertiesView-presentationTrails-title-icon">
diff --git a/src/client/views/SidebarAnnos.tsx b/src/client/views/SidebarAnnos.tsx
index c48a7241a..f3452c780 100644
--- a/src/client/views/SidebarAnnos.tsx
+++ b/src/client/views/SidebarAnnos.tsx
@@ -9,11 +9,11 @@ import { emptyFunction, returnAll, returnFalse, returnOne, returnTrue, returnZer
 import { Docs, DocUtils } from '../documents/Documents';
 import { CollectionViewType, DocumentType } from '../documents/DocumentTypes';
 import { LinkManager } from '../util/LinkManager';
+import { SearchUtil } from '../util/SearchUtil';
 import { Transform } from '../util/Transform';
 import { CollectionStackingView } from './collections/CollectionStackingView';
 import { FieldViewProps } from './nodes/FieldView';
 import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox';
-import { SearchBox } from './search/SearchBox';
 import './SidebarAnnos.scss';
 import { StyleProp } from './StyleProvider';
 import React = require('react');
@@ -43,7 +43,7 @@ export class SidebarAnnos extends React.Component<FieldViewProps & ExtraProps> {
     @computed get allMetadata() {
         const keys = new Map<string, FieldResult<Field>>();
         DocListCast(this.props.rootDoc[this.sidebarKey]).forEach(doc =>
-            SearchBox.documentKeys(doc)
+            SearchUtil.documentKeys(doc)
                 .filter(key => key[0] && key[0] !== '_' && key[0] === key[0].toUpperCase())
                 .map(key => keys.set(key, doc[key]))
         );
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index 24a269927..12935400b 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -4,6 +4,7 @@ import { Tooltip } from '@material-ui/core';
 import { IconButton, Shadows, Size } from 'browndash-components';
 import { action, runInAction } from 'mobx';
 import { extname } from 'path';
+import { BsArrowDown, BsArrowDownUp, BsArrowUp } from 'react-icons/bs';
 import { Doc, Opt, StrListCast } from '../../fields/Doc';
 import { BoolCast, Cast, DocCast, ImageCast, NumCast, StrCast } from '../../fields/Types';
 import { DashColor, lightOrDark, Utils } from '../../Utils';
@@ -14,15 +15,13 @@ import { LinkManager } from '../util/LinkManager';
 import { SelectionManager } from '../util/SelectionManager';
 import { ColorScheme, SettingsManager } from '../util/SettingsManager';
 import { undoBatch, UndoManager } from '../util/UndoManager';
-import { TreeSort } from './collections/TreeView';
+import { TreeSort } from './collections/TreeSort';
 import { Colors } from './global/globalEnums';
 import { InkingStroke } from './InkingStroke';
-import { MainView } from './MainView';
-import { DocumentViewProps } from './nodes/DocumentView';
+import { DocumentView, DocumentViewProps } from './nodes/DocumentView';
 import { FieldViewProps } from './nodes/FieldView';
 import { KeyValueBox } from './nodes/KeyValueBox';
 import { SliderBox } from './nodes/SliderBox';
-import { BsArrowDown, BsArrowUp, BsArrowDownUp } from 'react-icons/bs';
 import './StyleProvider.scss';
 import React = require('react');
 
@@ -159,7 +158,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
                 ''
             );
         case StyleProp.Color:
-            if (MainView.Instance.LastButton === doc) return SettingsManager.Instance.userBackgroundColor;
+            if (DocumentView.LastPressedSidebarBtn === doc) return SettingsManager.userBackgroundColor;
             if (Doc.IsSystem(doc!)) return StrCast(Doc.UserDoc().userColor)
             if (doc?.type === DocumentType.FONTICON) return Doc.UserDoc().userColor;
             const docColor: Opt<string> = StrCast(doc?.[fieldKey + 'color'], StrCast(doc?._color));
@@ -194,7 +193,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
                 ? 15
                 : 0;
         case StyleProp.BackgroundColor: {
-            if (MainView.Instance.LastButton === doc) return StrCast(Doc.UserDoc().userColor); // hack to indicate active menu panel item
+            if (DocumentView.LastPressedSidebarBtn === doc) return StrCast(Doc.UserDoc().userColor); // hack to indicate active menu panel item
             let docColor: Opt<string> = StrCast(doc?.[fieldKey + '_backgroundColor'], StrCast(doc?._backgroundColor, isCaption ? 'rgba(0,0,0,0.4)' : ''));
             // prettier-ignore
             switch (doc?.type) {
@@ -217,7 +216,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
                 case DocumentType.COL:
                     if (StrCast(Doc.LayoutField(doc)).includes(SliderBox.name)) break;
                     docColor = docColor || (Doc.IsSystem(doc)
-                            ? SettingsManager.Instance.userBackgroundColor
+                            ? SettingsManager.userBackgroundColor
                             : doc.annotationOn
                             ? '#00000010' // faint interior for collections on PDFs, images, etc
                             : doc?._isGroup
@@ -264,7 +263,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
             const isInk = doc && StrCast(Doc.Layout(doc).layout).includes(InkingStroke.name) && !props?.LayoutTemplateString;
             if (StrCast(doc?.pointerEvents) && !props?.LayoutTemplateString?.includes(KeyValueBox.name)) return StrCast(doc!.pointerEvents); // honor pointerEvents field (set by lock button usually) if it's not a keyValue view of the Doc
             if (docProps?.DocumentView?.().ComponentView?.overridePointerEvents?.() !== undefined) return docProps?.DocumentView?.().ComponentView?.overridePointerEvents?.();
-            if (MainView.Instance._exploreMode || doc?.layout_unrendered) return isInk ? 'visiblePainted' : 'all';
+            if (DocumentView.ExploreMode || doc?.layout_unrendered) return isInk ? 'visiblePainted' : 'all';
             if (props?.contentPointerEvents) return StrCast(props.contentPointerEvents);
             if (props?.pointerEvents?.() === 'none') return 'none';
             if (opacity() === 0) return 'none';
diff --git a/src/client/views/UndoStack.tsx b/src/client/views/UndoStack.tsx
index a551e5332..3fd64d1fd 100644
--- a/src/client/views/UndoStack.tsx
+++ b/src/client/views/UndoStack.tsx
@@ -19,7 +19,7 @@ export class UndoStack extends React.Component<UndoStackProps> {
     @observable static HideInline: boolean;
     @observable static Expand: boolean;
     render() {
-        const background = UndoManager.batchCounter.get() ? 'yellow' : SettingsManager.Instance.userBackgroundColor;
+        const background = UndoManager.batchCounter.get() ? 'yellow' : SettingsManager.userBackgroundColor;
         return this.props.inline && UndoStack.HideInline ? null : (
             <div className="undoStack-outerContainer">
                 <Popup
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index e15d57306..519b7c905 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -3,6 +3,7 @@ import { observer } from 'mobx-react';
 import * as ReactDOM from 'react-dom/client';
 import * as GoldenLayout from '../../../client/goldenLayout';
 import { Doc, DocListCast, Opt } from '../../../fields/Doc';
+import { AclAdmin, AclEdit } from '../../../fields/DocSymbols';
 import { Id } from '../../../fields/FieldSymbols';
 import { InkTool } from '../../../fields/InkField';
 import { List } from '../../../fields/List';
@@ -13,6 +14,7 @@ import { emptyFunction, incrementTitleCopy } from '../../../Utils';
 import { DocServer } from '../../DocServer';
 import { Docs } from '../../documents/Documents';
 import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes';
+import { DocumentManager } from '../../util/DocumentManager';
 import { DragManager } from '../../util/DragManager';
 import { InteractionUtils } from '../../util/InteractionUtils';
 import { ScriptingGlobals } from '../../util/ScriptingGlobals';
@@ -28,8 +30,6 @@ import './CollectionDockingView.scss';
 import { CollectionFreeFormView } from './collectionFreeForm';
 import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView';
 import { TabDocView } from './TabDocView';
-import { DocumentManager } from '../../util/DocumentManager';
-import { AclAdmin, AclEdit } from '../../../fields/DocSymbols';
 import React = require('react');
 const _global = (window /* browser */ || global) /* node */ as any;
 
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index f65e8698f..5c9dd2058 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -181,7 +181,7 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> {
             <div
                 className="collectionMenu-container"
                 style={{
-                    background: SettingsManager.Instance.userBackgroundColor,
+                    background: SettingsManager.userBackgroundColor,
                     // borderColor: StrCast(Doc.UserDoc().userColor)
                 }}>
                 {this.contMenuButtons}
diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index de58e1fe7..d2be70577 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -2,12 +2,12 @@ import React = require('react');
 import { action, computed, IReactionDisposer, observable, reaction } from 'mobx';
 import { observer } from 'mobx-react';
 import { computedFn } from 'mobx-utils';
-import { Doc, Opt, StrListCast } from '../../../fields/Doc';
+import { Doc, Opt } from '../../../fields/Doc';
 import { Id } from '../../../fields/FieldSymbols';
 import { List } from '../../../fields/List';
 import { listSpec } from '../../../fields/Schema';
 import { ComputedField, ScriptField } from '../../../fields/ScriptField';
-import { Cast, NumCast, ScriptCast } from '../../../fields/Types';
+import { Cast, NumCast } from '../../../fields/Types';
 import { ImageField } from '../../../fields/URLField';
 import { emptyFunction, formatTime, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnNone, returnTrue, returnZero, setupMoveUpEvents, smoothScrollHorizontal, StopEvent } from '../../../Utils';
 import { Docs } from '../../documents/Documents';
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index f379d09ff..f6acafa95 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -1,6 +1,6 @@
 import { IconProp } from '@fortawesome/fontawesome-svg-core';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { Tooltip } from '@material-ui/core';
+import { Popup, Type } from 'browndash-components';
 import { clamp } from 'lodash';
 import { action, computed, IReactionDisposer, observable, ObservableSet, reaction } from 'mobx';
 import { observer } from 'mobx-react';
@@ -10,7 +10,7 @@ import { DocData, Height, Width } from '../../../fields/DocSymbols';
 import { Id } from '../../../fields/FieldSymbols';
 import { List } from '../../../fields/List';
 import { FieldId } from '../../../fields/RefField';
-import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../fields/Types';
+import { Cast, DocCast, NumCast, StrCast } from '../../../fields/Types';
 import { emptyFunction, lightOrDark, returnEmptyDoclist, returnFalse, returnTrue, setupMoveUpEvents, simulateMouseClick, Utils } from '../../../Utils';
 import { DocServer } from '../../DocServer';
 import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes';
@@ -21,9 +21,8 @@ import { SnappingManager } from '../../util/SnappingManager';
 import { Transform } from '../../util/Transform';
 import { undoable, UndoManager } from '../../util/UndoManager';
 import { DashboardView } from '../DashboardView';
-import { Colors, Shadows } from '../global/globalEnums';
+import { Colors } from '../global/globalEnums';
 import { LightboxView } from '../LightboxView';
-import { MainView } from '../MainView';
 import { DocFocusOptions, DocumentView, DocumentViewProps, OpenWhere, OpenWhereMod } from '../nodes/DocumentView';
 import { DashFieldView } from '../nodes/formattedText/DashFieldView';
 import { KeyValueBox } from '../nodes/KeyValueBox';
@@ -34,7 +33,6 @@ import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormV
 import { CollectionView } from './CollectionView';
 import './TabDocView.scss';
 import React = require('react');
-import { Popup, Toggle, Type } from 'browndash-components';
 const _global = (window /* browser */ || global) /* node */ as any;
 
 interface TabDocViewProps {
@@ -426,6 +424,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
     disableMinimap = () => !this._document || this._document.layout !== CollectionView.LayoutString(Doc.LayoutFieldKey(this._document)) || this._document?._type_collection !== CollectionViewType.Freeform;
     whenChildContentActiveChanges = (isActive: boolean) => (this._isAnyChildContentActive = isActive);
     isContentActive = () => this._isContentActive;
+    waitForDoubleClick = () => (DocumentView.ExploreMode ? 'never' : undefined);
     @computed get docView() {
         return !this._activated || !this._document ? null : (
             <>
@@ -441,8 +440,8 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                     hideTitle={this.props.keyValue}
                     Document={this._document}
                     DataDoc={!Doc.AreProtosEqual(this._document[DocData], this._document) ? this._document[DocData] : undefined}
-                    onBrowseClick={MainView.Instance.exploreMode}
-                    waitForDoubleClickToClick={MainView.Instance.waitForDoubleClick}
+                    onBrowseClick={DocumentView.exploreMode}
+                    waitForDoubleClickToClick={this.waitForDoubleClick}
                     isContentActive={this.isContentActive}
                     isDocumentActive={returnFalse}
                     PanelWidth={this.PanelWidth}
diff --git a/src/client/views/collections/TreeSort.ts b/src/client/views/collections/TreeSort.ts
new file mode 100644
index 000000000..977acd030
--- /dev/null
+++ b/src/client/views/collections/TreeSort.ts
@@ -0,0 +1,6 @@
+export enum TreeSort {
+    AlphaUp = 'alphabetical from z',
+    AlphaDown = 'alphabetical from A',
+    Zindex = 'by Z index',
+    WhenAdded = 'when added',
+}
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 3402a8c8d..701150769 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -35,6 +35,7 @@ import { CollectionView } from './CollectionView';
 import './TreeView.scss';
 import React = require('react');
 import { IconButton, Size } from 'browndash-components';
+import { TreeSort } from './TreeSort';
 
 export interface TreeViewProps {
     treeView: CollectionTreeView;
@@ -77,12 +78,6 @@ const treeBulletWidth = function () {
     return Number(TREE_BULLET_WIDTH.replace('px', ''));
 };
 
-export enum TreeSort {
-    AlphaUp = 'alphabetical from z',
-    AlphaDown = 'alphabetical from A',
-    Zindex = 'by Z index',
-    WhenAdded = 'when added',
-}
 /**
  * Renders a treeView of a collection of documents
  *
@@ -578,7 +573,7 @@ export class TreeView extends React.Component<TreeViewProps> {
             return (
                 <div>
                     {!docs?.length || this.props.AddToMap /* hack to identify pres box trees */ ? null : (
-                        <div className='treeView-sorting'>
+                        <div className="treeView-sorting">
                             <IconButton
                                 color={sortings[sorting]?.color}
                                 size={Size.XSMALL}
@@ -602,7 +597,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                         style={{ cursor: 'inherit' }}
                         key={expandKey + 'more'}
                         title={`Sorted by : ${this.doc.treeView_SortCriterion}. click to cycle`}
-                        className='' //this.doc.treeView_HideTitle ? 'no-indent' : ''}
+                        className="" //this.doc.treeView_HideTitle ? 'no-indent' : ''}
                         onPointerDown={e => {
                             downX = e.clientX;
                             downY = e.clientY;
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index f5cc1eb53..16d6f1270 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -371,7 +371,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
             const nd = [Doc.NativeWidth(layoutDoc), Doc.NativeHeight(layoutDoc)];
             layoutDoc._width = NumCast(layoutDoc._width, 300);
             layoutDoc._height = NumCast(layoutDoc._height, nd[0] && nd[1] ? (nd[1] / nd[0]) * NumCast(layoutDoc._width) : 300);
-            (d._raiseWhenDragged === undefined ? DragManager.GetRaiseWhenDragged() : d._raiseWhenDragged) && (d.zIndex = zsorted.length + 1 + i); // bringToFront
+            !d._keepZWhenDragged && (d.zIndex = zsorted.length + 1 + i); // bringToFront
         }
 
         if (this.layoutDoc._autoArrange || de.metaKey) {
@@ -1267,7 +1267,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     };
     @computed get _pointerEvents() {
         const engine = this.props.layoutEngine?.() || StrCast(this.props.Document._layoutEngine);
-        const pointerEvents = DocumentDecorations.Instance.Interacting
+        const pointerEvents = DocumentView.Interacting
             ? 'none'
             : this.props.childPointerEvents ?? (this.props.viewDefDivClick || (engine === computePassLayout.name && !this.props.isSelected(true)) || this.isContentActive() === false ? 'none' : this.props.pointerEvents?.());
         return pointerEvents;
diff --git a/src/client/views/linking/LinkPopup.tsx b/src/client/views/linking/LinkPopup.tsx
index 6895c0746..9a9a89732 100644
--- a/src/client/views/linking/LinkPopup.tsx
+++ b/src/client/views/linking/LinkPopup.tsx
@@ -3,15 +3,14 @@ import { observer } from 'mobx-react';
 import { EditorView } from 'prosemirror-view';
 import { Doc } from '../../../fields/Doc';
 import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue } from '../../../Utils';
-import { DocUtils } from '../../documents/Documents';
 import { Transform } from '../../util/Transform';
 import { undoBatch } from '../../util/UndoManager';
+import { OpenWhere } from '../nodes/DocumentView';
 import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox';
 import { SearchBox } from '../search/SearchBox';
 import { DefaultStyleProvider } from '../StyleProvider';
 import './LinkPopup.scss';
 import React = require('react');
-import { OpenWhere } from '../nodes/DocumentView';
 
 interface LinkPopupProps {
     linkFrom?: () => Doc | undefined;
diff --git a/src/client/views/newlightbox/ButtonMenu/ButtonMenu.tsx b/src/client/views/newlightbox/ButtonMenu/ButtonMenu.tsx
index ff17e5c12..3a95e5f74 100644
--- a/src/client/views/newlightbox/ButtonMenu/ButtonMenu.tsx
+++ b/src/client/views/newlightbox/ButtonMenu/ButtonMenu.tsx
@@ -1,14 +1,13 @@
-import './ButtonMenu.scss';
+import { action } from 'mobx';
 import * as React from 'react';
-import { IButtonMenu } from './utils';
-import { NewLightboxView } from '../NewLightboxView';
-import { SelectionManager } from '../../../util/SelectionManager';
-import { CollectionDockingView } from '../../collections/CollectionDockingView';
-import { OpenWhereMod } from '../../nodes/DocumentView';
 import { Doc } from '../../../../fields/Doc';
 import { InkTool } from '../../../../fields/InkField';
-import { MainView } from '../../MainView';
-import { action } from 'mobx';
+import { SelectionManager } from '../../../util/SelectionManager';
+import { CollectionDockingView } from '../../collections/CollectionDockingView';
+import { DocumentView, OpenWhereMod } from '../../nodes/DocumentView';
+import { NewLightboxView } from '../NewLightboxView';
+import './ButtonMenu.scss';
+import { IButtonMenu } from './utils';
 
 export const ButtonMenu = (props: IButtonMenu) => {
     return (
@@ -40,10 +39,10 @@ export const ButtonMenu = (props: IButtonMenu) => {
             <div
                 className="newLightboxView-exploreBtn"
                 title="toggle explore mode to navigate among documents only"
-                style={{ background: MainView.Instance._exploreMode ? 'white' : undefined }}
+                style={{ background: DocumentView.ExploreMode ? 'white' : undefined }}
                 onClick={action(e => {
                     e.stopPropagation();
-                    MainView.Instance._exploreMode = !MainView.Instance._exploreMode;
+                    DocumentView.ExploreMode = !DocumentView.ExploreMode;
                 })}></div>
         </div>
     );
diff --git a/src/client/views/newlightbox/NewLightboxView.tsx b/src/client/views/newlightbox/NewLightboxView.tsx
index 3acbd1a32..ca90f6a0f 100644
--- a/src/client/views/newlightbox/NewLightboxView.tsx
+++ b/src/client/views/newlightbox/NewLightboxView.tsx
@@ -2,35 +2,32 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { action, computed, observable } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
-import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnTrue } from '../../../Utils';
-import { Doc, DocListCast, Opt, StrListCast } from '../../../fields/Doc';
+import { Doc, DocListCast, Opt } from '../../../fields/Doc';
 import { InkTool } from '../../../fields/InkField';
 import { Cast, NumCast, StrCast } from '../../../fields/Types';
+import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnTrue } from '../../../Utils';
 import { DocUtils } from '../../documents/Documents';
 import { DocumentManager } from '../../util/DocumentManager';
 import { LinkManager } from '../../util/LinkManager';
 import { SelectionManager } from '../../util/SelectionManager';
 import { Transform } from '../../util/Transform';
-import { GestureOverlay } from '../GestureOverlay';
-import { MainView } from '../MainView';
-import { DefaultStyleProvider } from '../StyleProvider';
 import { CollectionStackedTimeline } from '../collections/CollectionStackedTimeline';
 import { TabDocView } from '../collections/TabDocView';
+import { GestureOverlay } from '../GestureOverlay';
+import { LightboxView } from '../LightboxView';
 import { DocumentView, OpenWhere } from '../nodes/DocumentView';
+import { DefaultStyleProvider } from '../StyleProvider';
+import { IRecommendation } from './components';
 import { ExploreView } from './ExploreView';
-import { IBounds, emptyBounds } from './ExploreView/utils';
+import { emptyBounds, IBounds } from './ExploreView/utils';
 import { NewLightboxHeader } from './Header';
 import './NewLightboxView.scss';
 import { RecommendationList } from './RecommendationList';
-import { IRecommendation } from './components';
-import { fetchKeywords, fetchRecommendations } from './utils';
-import { List } from '../../../fields/List';
-import { LightboxView } from '../LightboxView';
 
 enum LightboxStatus {
-    RECOMMENDATIONS = "recommendations",
-    ANNOTATIONS = "annotations",
-    NONE = "none"
+    RECOMMENDATIONS = 'recommendations',
+    ANNOTATIONS = 'annotations',
+    NONE = 'none',
 }
 
 interface LightboxViewProps {
@@ -63,30 +60,30 @@ export class NewLightboxView extends React.Component<LightboxViewProps> {
     @observable private static _docView: Opt<DocumentView>;
 
     // keywords
-    @observable private static _keywords: string[] = []
+    @observable private static _keywords: string[] = [];
     @action public static SetKeywords(kw: string[]) {
-        this._keywords = kw
+        this._keywords = kw;
     }
     @computed public static get Keywords() {
-        return this._keywords
+        return this._keywords;
     }
 
     // query
-    @observable private static _query: string = ''
+    @observable private static _query: string = '';
     @action public static SetQuery(query: string) {
-        this._query = query
+        this._query = query;
     }
     @computed public static get Query() {
-        return this._query
+        return this._query;
     }
 
     // keywords
-    @observable private static _recs: IRecommendation[] = []
+    @observable private static _recs: IRecommendation[] = [];
     @action public static SetRecs(recs: IRecommendation[]) {
-        this._recs = recs
+        this._recs = recs;
     }
     @computed public static get Recs() {
-        return this._recs
+        return this._recs;
     }
 
     // bounds
@@ -108,7 +105,7 @@ export class NewLightboxView extends React.Component<LightboxViewProps> {
     }
 
     // newLightbox sidebar status
-    @observable private static _sidebarStatus: Opt<string> = "";
+    @observable private static _sidebarStatus: Opt<string> = '';
     @action public static SetSidebarStatus(sidebarStatus: Opt<string>) {
         this._sidebarStatus = sidebarStatus;
     }
@@ -129,7 +126,7 @@ export class NewLightboxView extends React.Component<LightboxViewProps> {
             this._docFilters && (this._docFilters.length = 0);
             this._future = this._history = [];
             Doc.ActiveTool = InkTool.None;
-            MainView.Instance._exploreMode = false;
+            DocumentView.ExploreMode = false;
         } else {
             const l = DocUtils.MakeLinkToActiveAudio(() => doc).lastElement();
             l && (Cast(l.link_anchor_2, Doc, null).backgroundColor = 'lightgreen');
@@ -289,35 +286,38 @@ export class NewLightboxView extends React.Component<LightboxViewProps> {
 
     @computed
     get documentView() {
-        if (!LightboxView.LightboxDoc) return null
-        else return (<GestureOverlay isActive={true}>
-                            <DocumentView
-                                ref={action((r: DocumentView | null) => (NewLightboxView._docView = r !== null ? r : undefined))}
-                                Document={LightboxView.LightboxDoc}
-                                DataDoc={undefined}
-                                PanelWidth={this.newLightboxWidth}
-                                PanelHeight={this.newLightboxHeight}
-                                LayoutTemplate={NewLightboxView.LightboxDocTemplate}
-                                isDocumentActive={returnTrue} // without this being true, sidebar annotations need to be activated before text can be selected.
-                                isContentActive={returnTrue}
-                                styleProvider={DefaultStyleProvider}
-                                ScreenToLocalTransform={this.newLightboxScreenToLocal}
-                                renderDepth={0}
-                                rootSelected={returnTrue}
-                                docViewPath={returnEmptyDoclist}
-                                childFilters={this.docFilters}
-                                childFiltersByRanges={returnEmptyFilter}
-                                searchFilterDocs={returnEmptyDoclist}
-                                addDocument={undefined}
-                                removeDocument={undefined}
-                                whenChildContentsActiveChanged={emptyFunction}
-                                addDocTab={this.addDocTab}
-                                pinToPres={TabDocView.PinDoc}
-                                bringToFront={emptyFunction}
-                                onBrowseClick={MainView.Instance.exploreMode}
-                                focus={emptyFunction}
-                            />
-                        </GestureOverlay>)
+        if (!LightboxView.LightboxDoc) return null;
+        else
+            return (
+                <GestureOverlay isActive={true}>
+                    <DocumentView
+                        ref={action((r: DocumentView | null) => (NewLightboxView._docView = r !== null ? r : undefined))}
+                        Document={LightboxView.LightboxDoc}
+                        DataDoc={undefined}
+                        PanelWidth={this.newLightboxWidth}
+                        PanelHeight={this.newLightboxHeight}
+                        LayoutTemplate={NewLightboxView.LightboxDocTemplate}
+                        isDocumentActive={returnTrue} // without this being true, sidebar annotations need to be activated before text can be selected.
+                        isContentActive={returnTrue}
+                        styleProvider={DefaultStyleProvider}
+                        ScreenToLocalTransform={this.newLightboxScreenToLocal}
+                        renderDepth={0}
+                        rootSelected={returnTrue}
+                        docViewPath={returnEmptyDoclist}
+                        childFilters={this.docFilters}
+                        childFiltersByRanges={returnEmptyFilter}
+                        searchFilterDocs={returnEmptyDoclist}
+                        addDocument={undefined}
+                        removeDocument={undefined}
+                        whenChildContentsActiveChanged={emptyFunction}
+                        addDocTab={this.addDocTab}
+                        pinToPres={TabDocView.PinDoc}
+                        bringToFront={emptyFunction}
+                        onBrowseClick={DocumentView.exploreMode}
+                        focus={emptyFunction}
+                    />
+                </GestureOverlay>
+            );
     }
 
     future = () => NewLightboxView._future;
@@ -337,29 +337,28 @@ export class NewLightboxView extends React.Component<LightboxViewProps> {
                         NewLightboxView.SetNewLightboxDoc(undefined);
                     }
                 }}>
-                <div className={`app-document`} style={{gridTemplateColumns: `calc(100% - 400px) 400px`}}>
-                <div
-                    className="newLightboxView-contents"
-                    style={{
-                        top: 20,
-                        left: 20,
-                        width: this.newLightboxWidth(),
-                        height: this.newLightboxHeight() - 40,
-                    }}>
+                <div className={`app-document`} style={{ gridTemplateColumns: `calc(100% - 400px) 400px` }}>
+                    <div
+                        className="newLightboxView-contents"
+                        style={{
+                            top: 20,
+                            left: 20,
+                            width: this.newLightboxWidth(),
+                            height: this.newLightboxHeight() - 40,
+                        }}>
                         <NewLightboxHeader height={newLightboxHeaderHeight} width={this.newLightboxWidth()} />
-                        {!NewLightboxView._explore ? 
-                            <div className="newLightboxView-doc" style={{height: this.newLightboxHeight()}}>
+                        {!NewLightboxView._explore ? (
+                            <div className="newLightboxView-doc" style={{ height: this.newLightboxHeight() }}>
                                 {this.documentView}
                             </div>
-                        :
+                        ) : (
                             <div className={`explore`}>
-                                <ExploreView recs={NewLightboxView.Recs} bounds={NewLightboxView.Bounds}/>
+                                <ExploreView recs={NewLightboxView.Recs} bounds={NewLightboxView.Bounds} />
                             </div>
-                        }
-                </div>
-                    <RecommendationList keywords={NewLightboxView.Keywords}/>
+                        )}
+                    </div>
+                    <RecommendationList keywords={NewLightboxView.Keywords} />
                 </div>
-                
             </div>
         );
     }
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index be1eb3901..74eee49e0 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -28,6 +28,7 @@ import { FollowLinkScript } from '../../util/LinkFollower';
 import { LinkManager } from '../../util/LinkManager';
 import { ScriptingGlobals } from '../../util/ScriptingGlobals';
 import { SelectionManager } from '../../util/SelectionManager';
+import { SettingsManager } from '../../util/SettingsManager';
 import { SharingManager } from '../../util/SharingManager';
 import { SnappingManager } from '../../util/SnappingManager';
 import { Transform } from '../../util/Transform';
@@ -51,7 +52,6 @@ import { LinkAnchorBox } from './LinkAnchorBox';
 import { PresEffect, PresEffectDirection } from './trails';
 import { PinProps, PresBox } from './trails/PresBox';
 import React = require('react');
-import { SettingsManager } from '../../util/SettingsManager';
 const { Howl } = require('howler');
 
 interface Window {
@@ -428,7 +428,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
         if (!this.Document.ignoreClick && this.pointerEvents !== 'none' && this.props.renderDepth >= 0 && Utils.isClick(e.clientX, e.clientY, this._downX, this._downY, this._downTime)) {
             let stopPropagate = true;
             let preventDefault = true;
-            (this.rootDoc._raiseWhenDragged === undefined ? DragManager.GetRaiseWhenDragged() : this.rootDoc._raiseWhenDragged) && this.props.bringToFront(this.rootDoc);
+            !this.rootDoc._keepZWhenDragged && this.props.bringToFront(this.rootDoc);
             if (this._doubleTap) {
                 const defaultDblclick = this.props.defaultDoubleClick?.() || this.Document.defaultDoubleClick;
                 if (this.onDoubleClickHandler?.script) {
@@ -744,8 +744,8 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                     zorderItems.push({ description: 'Bring to Front', event: () => SelectionManager.Views().forEach(dv => dv.props.bringToFront(dv.rootDoc, false)), icon: 'arrow-up' });
                     zorderItems.push({ description: 'Send to Back', event: () => SelectionManager.Views().forEach(dv => dv.props.bringToFront(dv.rootDoc, true)), icon: 'arrow-down' });
                     zorderItems.push({
-                        description: this.rootDoc._raiseWhenDragged !== false ? 'Keep ZIndex when dragged' : 'Allow ZIndex to change when dragged',
-                        event: undoBatch(action(() => (this.rootDoc._raiseWhenDragged = this.rootDoc._raiseWhenDragged === undefined ? false : undefined))),
+                        description: !this.rootDoc._keepZDragged ? 'Keep ZIndex when dragged' : 'Allow ZIndex to change when dragged',
+                        event: undoBatch(action(() => (this.rootDoc._keepZWhenDragged = !this.rootDoc._keepZWhenDragged))),
                         icon: 'hand-point-up',
                     });
                     !zorders && cm.addItem({ description: 'Z Order...', addDivider: true, noexpand: true, subitems: zorderItems, icon: 'layer-group' });
@@ -1114,7 +1114,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
             </div>
         );
         const targetDoc = showTitle?.startsWith('_') ? this.layoutDoc : this.rootDoc;
-        const background = StrCast(SharingManager.Instance.users.find(u => u.user.email === this.dataDoc.author)?.sharingDoc.headingColor, StrCast(Doc.SharingDoc().headingColor, SettingsManager.Instance.userVariantColor));
+        const background = StrCast(SharingManager.Instance.users.find(u => u.user.email === this.dataDoc.author)?.sharingDoc.headingColor, StrCast(Doc.SharingDoc().headingColor, SettingsManager.userVariantColor));
         const sidebarWidthPercent = +StrCast(this.layoutDoc.layout_sidebarWidthPercent).replace('%', '');
         const titleView = !showTitle ? null : (
             <div
@@ -1276,7 +1276,13 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
 @observer
 export class DocumentView extends React.Component<DocumentViewProps> {
     public static ROOT_DIV = 'documentView-effectsWrapper';
+    @observable public static Interacting = false;
     @observable public static LongPress = false;
+    @observable public static ExploreMode = false;
+    @observable public static LastPressedSidebarBtn: Opt<Doc>; // bcz: this is a hack to handle highlighting buttons in the leftpanel menu .. need to find a cleaner approach
+    @computed public static get exploreMode() {
+        return () => (DocumentView.ExploreMode ? ScriptField.MakeScript('CollectionBrowseClick(documentView, clientX, clientY)', { documentView: 'any', clientX: 'number', clientY: 'number' })! : undefined);
+    }
     @observable public docView: DocumentViewInternal | undefined | null;
     @observable public textHtmlOverlay: Opt<string>;
     @observable private _isHovering = false;
diff --git a/src/client/views/nodes/FontIconBox/FontIconBox.tsx b/src/client/views/nodes/FontIconBox/FontIconBox.tsx
index 94650cc88..fc66d40db 100644
--- a/src/client/views/nodes/FontIconBox/FontIconBox.tsx
+++ b/src/client/views/nodes/FontIconBox/FontIconBox.tsx
@@ -67,19 +67,6 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
         }
     };
 
-    static GetShowLabels() {
-        return BoolCast(Doc.UserDoc()._showLabel);
-    }
-    static SetShowLabels(show: boolean) {
-        Doc.UserDoc()._showLabel = show;
-    }
-    static GetRecognizeGestures() {
-        return BoolCast(Doc.UserDoc()._recognizeGestures);
-    }
-    static SetRecognizeGestures(show: boolean) {
-        Doc.UserDoc()._recognizeGestures = show;
-    }
-
     // Determining UI Specs
     @computed get label() {
         return StrCast(this.rootDoc.icon_label, StrCast(this.rootDoc.title));
@@ -139,7 +126,7 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
         const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color);
         // Script for checking the outcome of the toggle
         const checkResult = Number(Number(numScript().result ?? 0).toPrecision(NumCast(this.dataDoc.numPrecision, 3)));
-        const label = !FontIconBox.GetShowLabels() ? null : <div className="fontIconBox-label">{this.label}</div>;
+        const label = !Doc.GetShowIconLabels() ? null : <div className="fontIconBox-label">{this.label}</div>;
 
         return (
             <NumberDropdown
@@ -174,7 +161,7 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
                     Doc.UnBrushAllDocs();
                 })}>
                 {this.Icon(color)}
-                {!this.label || !FontIconBox.GetShowLabels() ? null : (
+                {!this.label || !Doc.GetShowIconLabels() ? null : (
                     <div className="fontIconBox-label" style={{ color: color, backgroundColor: backgroundColor }}>
                         {' '}
                         {this.label}{' '}
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx
index d69009415..42c8ea6a4 100644
--- a/src/client/views/nodes/LinkDocPreview.tsx
+++ b/src/client/views/nodes/LinkDocPreview.tsx
@@ -4,7 +4,7 @@ import { action, computed, observable } from 'mobx';
 import { observer } from 'mobx-react';
 import wiki from 'wikijs';
 import { Doc, DocCastAsync, Opt } from '../../../fields/Doc';
-import { DirectLinks, Height, Width } from '../../../fields/DocSymbols';
+import { Height, Width } from '../../../fields/DocSymbols';
 import { Cast, DocCast, NumCast, PromiseValue, StrCast } from '../../../fields/Types';
 import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnNone, setupMoveUpEvents } from '../../../Utils';
 import { DocServer } from '../../DocServer';
@@ -13,9 +13,9 @@ import { DocumentType } from '../../documents/DocumentTypes';
 import { DragManager } from '../../util/DragManager';
 import { LinkFollower } from '../../util/LinkFollower';
 import { LinkManager } from '../../util/LinkManager';
+import { SearchUtil } from '../../util/SearchUtil';
 import { SettingsManager } from '../../util/SettingsManager';
 import { Transform } from '../../util/Transform';
-import { SearchBox } from '../search/SearchBox';
 import { DocumentView, DocumentViewSharedProps, OpenWhere } from './DocumentView';
 import './LinkDocPreview.scss';
 import React = require('react');
@@ -174,7 +174,7 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
             LinkFollower.FollowLink(this._linkDoc, this._linkSrc, false);
         } else if (this.props.hrefs?.length) {
             const webDoc =
-                Array.from(SearchBox.staticSearchCollection(Doc.MyFilesystem, this.props.hrefs[0]).keys()).lastElement() ??
+                Array.from(SearchUtil.SearchCollection(Doc.MyFilesystem, this.props.hrefs[0]).keys()).lastElement() ??
                 Docs.Create.WebDocument(this.props.hrefs[0], { title: this.props.hrefs[0], _nativeWidth: 850, _width: 200, _height: 400, data_useCors: true });
             this.props.docProps?.addDocTab(webDoc, OpenWhere.lightbox);
         }
diff --git a/src/client/views/nodes/LoadingBox.tsx b/src/client/views/nodes/LoadingBox.tsx
index fcbd0128d..0b02626e9 100644
--- a/src/client/views/nodes/LoadingBox.tsx
+++ b/src/client/views/nodes/LoadingBox.tsx
@@ -1,14 +1,14 @@
-import { action, observable, runInAction } from 'mobx';
+import { observable, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
 import ReactLoading from 'react-loading';
 import { Doc } from '../../../fields/Doc';
+import { Id } from '../../../fields/FieldSymbols';
 import { StrCast } from '../../../fields/Types';
 import { Networking } from '../../Network';
 import { ViewBoxAnnotatableComponent } from '../DocComponent';
 import { FieldView, FieldViewProps } from './FieldView';
 import './LoadingBox.scss';
-import { Id } from '../../../fields/FieldSymbols';
 
 /**
  * LoadingBox Class represents a placeholder doc for documents that are currently
@@ -44,7 +44,7 @@ export class LoadingBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
             this.rootDoc.loadingError = 'Upload interrupted, please try again';
         } else {
             const updateFunc = async () => {
-                const result = await Networking.QueryYoutubeProgress(StrCast(this.rootDoc[Id])); // We use the guid of the overwriteDoc to track file uploads. 
+                const result = await Networking.QueryYoutubeProgress(StrCast(this.rootDoc[Id])); // We use the guid of the overwriteDoc to track file uploads.
                 runInAction(() => (this.progress = result.progress));
                 this._timer = setTimeout(updateFunc, 1000);
             };
diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx
index 83a29f071..fa19caae1 100644
--- a/src/client/views/nodes/ScreenshotBox.tsx
+++ b/src/client/views/nodes/ScreenshotBox.tsx
@@ -314,7 +314,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
                             </>
                         </CollectionFreeFormView>
                     </div>
-                    <div style={{ background: SettingsManager.Instance.userColor, position: 'relative', height: this.formattedPanelHeight() }}>
+                    <div style={{ background: SettingsManager.userColor, position: 'relative', height: this.formattedPanelHeight() }}>
                         {!(this.dataDoc[this.fieldKey + '_dictation'] instanceof Doc) ? null : (
                             <FormattedTextBox
                                 {...this.props}
@@ -336,8 +336,8 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
                     </div>
                 </div>
                 {!this.props.isSelected() ? null : (
-                    <div className="screenshotBox-uiButtons" style={{ background: SettingsManager.Instance.userColor }}>
-                        <div className="screenshotBox-recorder" style={{ color: SettingsManager.Instance.userBackgroundColor, background: SettingsManager.Instance.userVariantColor }} key="snap" onPointerDown={this.toggleRecording}>
+                    <div className="screenshotBox-uiButtons" style={{ background: SettingsManager.userColor }}>
+                        <div className="screenshotBox-recorder" style={{ color: SettingsManager.userBackgroundColor, background: SettingsManager.userVariantColor }} key="snap" onPointerDown={this.toggleRecording}>
                             <FontAwesomeIcon icon="file" size="lg" />
                         </div>
                     </div>
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 2177adeff..48716b867 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -26,11 +26,10 @@ import { CollectionStackedTimeline, TrimScope } from '../collections/CollectionS
 import { ContextMenu } from '../ContextMenu';
 import { ContextMenuProps } from '../ContextMenuItem';
 import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent';
-import { DocumentDecorations } from '../DocumentDecorations';
 import { MarqueeAnnotator } from '../MarqueeAnnotator';
 import { AnchorMenu } from '../pdf/AnchorMenu';
 import { StyleProp } from '../StyleProvider';
-import { OpenWhere } from './DocumentView';
+import { DocumentView, OpenWhere } from './DocumentView';
 import { FieldView, FieldViewProps } from './FieldView';
 import { RecordingBox } from './RecordingBox';
 import { PinProps, PresBox } from './trails';
@@ -624,7 +623,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                 () => !this._playing && this.Seek(NumCast(this.layoutDoc._layout_currentTimecode))
             );
             this._disposers.youtubeReactionDisposer = reaction(
-                () => Doc.ActiveTool === InkTool.None && this.props.isSelected(true) && !SnappingManager.GetIsDragging() && !DocumentDecorations.Instance.Interacting,
+                () => Doc.ActiveTool === InkTool.None && this.props.isSelected(true) && !SnappingManager.GetIsDragging() && !DocumentView.Interacting,
                 interactive => (iframe.style.pointerEvents = interactive ? 'all' : 'none'),
                 { fireImmediately: true }
             );
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 200d06a0b..bd969b527 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -11,9 +11,10 @@ import { keymap } from 'prosemirror-keymap';
 import { Fragment, Mark, Node, Slice } from 'prosemirror-model';
 import { EditorState, NodeSelection, Plugin, TextSelection, Transaction } from 'prosemirror-state';
 import { EditorView } from 'prosemirror-view';
+import { BsMarkdownFill } from 'react-icons/bs';
 import { DateField } from '../../../../fields/DateField';
-import { Doc, DocListCast, StrListCast, Field, Opt } from '../../../../fields/Doc';
-import { AclAdmin, AclAugment, AclEdit, AclSelfEdit, DocCss, Height, Width, ForceServerWrite, UpdatingFromServer } from '../../../../fields/DocSymbols';
+import { Doc, DocListCast, Field, Opt } from '../../../../fields/Doc';
+import { AclAdmin, AclAugment, AclEdit, AclSelfEdit, DocCss, ForceServerWrite, Height, UpdatingFromServer, Width } from '../../../../fields/DocSymbols';
 import { Id } from '../../../../fields/FieldSymbols';
 import { InkTool } from '../../../../fields/InkField';
 import { List } from '../../../../fields/List';
@@ -25,11 +26,10 @@ import { BoolCast, Cast, DocCast, FieldValue, NumCast, ScriptCast, StrCast } fro
 import { GetEffectiveAcl, TraceMobx } from '../../../../fields/util';
 import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, numberRange, returnFalse, returnZero, setupMoveUpEvents, smoothScroll, unimplementedFunction, Utils } from '../../../../Utils';
 import { GoogleApiClientUtils, Pulls, Pushes } from '../../../apis/google_docs/GoogleApiClientUtils';
-import { gptAPICall, GPTCallType, gptImageCall } from '../../../apis/gpt/GPT';
+import { gptAPICall, GPTCallType } from '../../../apis/gpt/GPT';
 import { DocServer } from '../../../DocServer';
 import { Docs, DocUtils } from '../../../documents/Documents';
-import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes';
-import { Networking } from '../../../Network';
+import { CollectionViewType } from '../../../documents/DocumentTypes';
 import { DictationManager } from '../../../util/DictationManager';
 import { DocumentManager } from '../../../util/DocumentManager';
 import { DragManager } from '../../../util/DragManager';
@@ -49,6 +49,7 @@ import { DocumentButtonBar } from '../../DocumentButtonBar';
 import { Colors } from '../../global/globalEnums';
 import { LightboxView } from '../../LightboxView';
 import { AnchorMenu } from '../../pdf/AnchorMenu';
+import { GPTPopup } from '../../pdf/GPTPopup/GPTPopup';
 import { SidebarAnnos } from '../../SidebarAnnos';
 import { StyleProp } from '../../StyleProvider';
 import { DocFocusOptions, DocumentView, DocumentViewInternal, OpenWhere } from '../DocumentView';
@@ -70,8 +71,6 @@ import { schema } from './schema_rts';
 import { SummaryView } from './SummaryView';
 import applyDevTools = require('prosemirror-dev-tools');
 import React = require('react');
-import { GPTPopup, GPTPopupMode } from '../../pdf/GPTPopup/GPTPopup';
-import { BsMarkdownFill } from 'react-icons/bs';
 const translateGoogleApi = require('translate-google-api');
 export const GoogleRef = 'googleDocId';
 type PullHandler = (exportState: Opt<GoogleApiClientUtils.Docs.ImportResult>, dataDoc: Doc) => void;
@@ -575,7 +574,14 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                         draggedDoc._freeform_fitContentsToBox = true;
                         Doc.SetContainer(draggedDoc, this.rootDoc);
                         const view = this._editorView!;
-                        view.dispatch(view.state.tr.insert(view.posAtCoords({ left: de.x, top: de.y })!.pos, node));
+                        try {
+                            const pos = view.posAtCoords({ left: de.x, top: de.y })?.pos;
+                            pos && view.dispatch(view.state.tr.insert(pos, node));
+                            added = pos ? true : false; // pos will be null if you don't drop onto an actual text location
+                        } catch (e) {
+                            console.log('Drop failed', e);
+                            added = false;
+                        }
                     }
                 }
             } // otherwise, fall through to outer collection to handle drop
@@ -1119,7 +1125,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
     componentDidMount() {
         !this.props.dontSelectOnLoad && this.props.setContentView?.(this); // this tells the DocumentView that this AudioBox is the "content" of the document.  this allows the DocumentView to indirectly call getAnchor() on the AudioBox when making a link.
         this._cachedLinks = LinkManager.Links(this.Document);
-        this._disposers.breakupDictation = reaction(() => DocumentManager.Instance.RecordingEvent, this.breakupDictation);
+        this._disposers.breakupDictation = reaction(() => Doc.RecordingEvent, this.breakupDictation);
         this._disposers.layout_autoHeight = reaction(
             () => this.layout_autoHeight,
             layout_autoHeight => layout_autoHeight && this.tryUpdateScrollHeight()
diff --git a/src/client/views/nodes/generativeFill/GenerativeFill.tsx b/src/client/views/nodes/generativeFill/GenerativeFill.tsx
index 1400d0f6d..1ec6d6e3f 100644
--- a/src/client/views/nodes/generativeFill/GenerativeFill.tsx
+++ b/src/client/views/nodes/generativeFill/GenerativeFill.tsx
@@ -1,26 +1,25 @@
-import './GenerativeFill.scss';
-import React = require('react');
-import { useEffect, useRef, useState } from 'react';
-import { APISuccess, ImageUtility } from './generativeFillUtils/ImageHandler';
-import { BrushHandler } from './generativeFillUtils/BrushHandler';
-import { IconButton } from 'browndash-components';
 import { Checkbox, FormControlLabel, Slider, TextField } from '@mui/material';
-import { CursorData, ImageDimensions, Point } from './generativeFillUtils/generativeFillInterfaces';
-import { activeColor, canvasSize, eraserColor, freeformRenderSize, newCollectionSize, offsetDistanceY, offsetX } from './generativeFillUtils/generativeFillConstants';
-import { PointerHandler } from './generativeFillUtils/PointerHandler';
-import { IoMdUndo, IoMdRedo } from 'react-icons/io';
-import { MainView } from '../../MainView';
+import { IconButton } from 'browndash-components';
+import { useEffect, useRef, useState } from 'react';
+import { CgClose } from 'react-icons/cg';
+import { IoMdRedo, IoMdUndo } from 'react-icons/io';
 import { Doc, DocListCast } from '../../../../fields/Doc';
-import { Networking } from '../../../Network';
-import { Utils } from '../../../../Utils';
-import { DocUtils, Docs } from '../../../documents/Documents';
+import { List } from '../../../../fields/List';
 import { NumCast } from '../../../../fields/Types';
+import { Utils } from '../../../../Utils';
+import { Docs, DocUtils } from '../../../documents/Documents';
+import { Networking } from '../../../Network';
 import { CollectionDockingView } from '../../collections/CollectionDockingView';
 import { OpenWhereMod } from '../DocumentView';
-import Buttons from './GenerativeFillButtons';
-import { List } from '../../../../fields/List';
-import { CgClose } from 'react-icons/cg';
 import { ImageBox } from '../ImageBox';
+import './GenerativeFill.scss';
+import Buttons from './GenerativeFillButtons';
+import { BrushHandler } from './generativeFillUtils/BrushHandler';
+import { activeColor, canvasSize, eraserColor, freeformRenderSize, newCollectionSize, offsetDistanceY, offsetX } from './generativeFillUtils/generativeFillConstants';
+import { CursorData, ImageDimensions, Point } from './generativeFillUtils/generativeFillInterfaces';
+import { APISuccess, ImageUtility } from './generativeFillUtils/ImageHandler';
+import { PointerHandler } from './generativeFillUtils/PointerHandler';
+import React = require('react');
 
 enum BrushStyle {
     ADD,
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index 6ff22e929..f750392f5 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -3,7 +3,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { Tooltip } from '@material-ui/core';
 import { action, computed, IReactionDisposer, observable, ObservableSet, reaction, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
-import { Doc, DocListCast, Field, FieldResult, Opt, StrListCast } from '../../../../fields/Doc';
+import { Doc, DocListCast, FieldResult, Opt, StrListCast } from '../../../../fields/Doc';
 import { Animation } from '../../../../fields/DocSymbols';
 import { Copy, Id } from '../../../../fields/FieldSymbols';
 import { InkField } from '../../../../fields/InkField';
@@ -15,7 +15,7 @@ import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../../fields/Ty
 import { AudioField } from '../../../../fields/URLField';
 import { emptyFunction, emptyPath, returnFalse, returnOne, setupMoveUpEvents, StopEvent } from '../../../../Utils';
 import { DocServer } from '../../../DocServer';
-import { Docs, DocUtils } from '../../../documents/Documents';
+import { Docs } from '../../../documents/Documents';
 import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes';
 import { DocumentManager } from '../../../util/DocumentManager';
 import { ScriptingGlobals } from '../../../util/ScriptingGlobals';
diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx
index b0924888a..6a8b06377 100644
--- a/src/client/views/pdf/AnchorMenu.tsx
+++ b/src/client/views/pdf/AnchorMenu.tsx
@@ -1,23 +1,20 @@
 import React = require('react');
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { Tooltip } from '@material-ui/core';
+import { ColorPicker, Group, IconButton, Popup, Size, Toggle, ToggleType, Type } from 'browndash-components';
 import { action, computed, IReactionDisposer, observable, ObservableMap, reaction } from 'mobx';
 import { observer } from 'mobx-react';
+import { EditorView } from 'prosemirror-view';
 import { ColorState } from 'react-color';
 import { Doc, Opt } from '../../../fields/Doc';
+import { StrCast } from '../../../fields/Types';
 import { returnFalse, setupMoveUpEvents, unimplementedFunction, Utils } from '../../../Utils';
+import { gptAPICall, GPTCallType } from '../../apis/gpt/GPT';
+import { DocumentType } from '../../documents/DocumentTypes';
 import { SelectionManager } from '../../util/SelectionManager';
 import { AntimodeMenu, AntimodeMenuProps } from '../AntimodeMenu';
 import { LinkPopup } from '../linking/LinkPopup';
-import { ButtonDropdown } from '../nodes/formattedText/RichTextMenu';
-import { gptAPICall, GPTCallType } from '../../apis/gpt/GPT';
-import { GPTPopup, GPTPopupMode } from './GPTPopup/GPTPopup';
-import { LightboxView } from '../LightboxView';
-import { EditorView } from 'prosemirror-view';
 import './AnchorMenu.scss';
-import { ColorPicker, Group, IconButton, Popup, Size, Toggle, ToggleType, Type } from 'browndash-components';
-import { StrCast } from '../../../fields/Types';
-import { DocumentType } from '../../documents/DocumentTypes';
+import { GPTPopup, GPTPopupMode } from './GPTPopup/GPTPopup';
 
 @observer
 export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
diff --git a/src/client/views/search/IconBar.tsx b/src/client/views/search/IconBar.tsx
index 6103b245c..540c1b5e1 100644
--- a/src/client/views/search/IconBar.tsx
+++ b/src/client/views/search/IconBar.tsx
@@ -1,17 +1,15 @@
 import { action, observable } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
-import { DocumentType } from "../../documents/DocumentTypes";
-// import "./SearchBox.scss";
-import "./IconBar.scss";
+import { DocumentType } from '../../documents/DocumentTypes';
+import './IconBar.scss';
 import { IconButton } from './IconButton';
-import "./IconButton.scss";
+import './IconButton.scss';
 
 export interface IconBarProps {
     setIcons: (icons: string[]) => void;
 }
 
-
 @observer
 export class IconBar extends React.Component<IconBarProps> {
     public _allIcons: string[] = [DocumentType.AUDIO, DocumentType.COL, DocumentType.IMG, DocumentType.LINK, DocumentType.PDF, DocumentType.RTF, DocumentType.VID, DocumentType.WEB, DocumentType.MAP];
@@ -32,7 +30,9 @@ export class IconBar extends React.Component<IconBarProps> {
     }
 
     @action.bound
-    getIcons(): string[] { return this._icons; }
+    getIcons(): string[] {
+        return this._icons;
+    }
 
     constructor(props: any) {
         super(props);
@@ -40,29 +40,33 @@ export class IconBar extends React.Component<IconBarProps> {
     }
 
     @action.bound
-    getList(): string[] { return this.getIcons(); }
+    getList(): string[] {
+        return this.getIcons();
+    }
 
     @action.bound
-    updateList(newList: string[]) { this.updateIcon(newList); }
+    updateList(newList: string[]) {
+        this.updateIcon(newList);
+    }
 
     @action.bound
     resetSelf = () => {
         this._resetClicked = true;
         this.updateList([]);
-    }
+    };
 
     @action.bound
     selectAll = () => {
         this._selectAllClicked = true;
         this.updateList(this._allIcons);
-    }
+    };
 
     render() {
         return (
             <div className="icon-bar">
-                {this._allIcons.map((type: string) =>
+                {this._allIcons.map((type: string) => (
                     <IconButton key={type.toString()} type={type} />
-                )}
+                ))}
             </div>
         );
     }
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 1ceea697a..6b6b0f2ff 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -19,6 +19,7 @@ import { fetchRecommendations } from '../newlightbox/utils';
 import { IRecommendation, Recommendation } from '../newlightbox/components';
 import { Colors } from '../global/globalEnums';
 import { SettingsManager } from '../../util/SettingsManager';
+import { SearchUtil } from '../../util/SearchUtil';
 
 const DAMPENING_FACTOR = 0.9;
 const MAX_ITERATIONS = 25;
@@ -128,34 +129,6 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
         }
     });
 
-    /**
-     * @param {Doc[]} docs - docs to be searched through recursively
-     * @param {number, Doc => void} func - function to be called on each doc
-     *
-     * This method iterates through an array of docs and all docs within those docs, calling
-     * the function func on each doc.
-     */
-    static foreachRecursiveDoc(docs: Doc[], func: (depth: number, doc: Doc) => void) {
-        let newarray: Doc[] = [];
-        var depth = 0;
-        const visited: Doc[] = [];
-        while (docs.length > 0) {
-            newarray = [];
-            docs.filter(d => d && !visited.includes(d)).forEach(d => {
-                visited.push(d);
-                const fieldKey = Doc.LayoutFieldKey(d);
-                const annos = !Field.toString(Doc.LayoutField(d) as Field).includes('CollectionView');
-                const data = d[annos ? fieldKey + '_annotations' : fieldKey];
-                data && newarray.push(...DocListCast(data));
-                const sidebar = d[fieldKey + '_sidebar'];
-                sidebar && newarray.push(...DocListCast(sidebar));
-                func(depth, d);
-            });
-            docs = newarray;
-            depth++;
-        }
-    }
-
     /**
      * @param {Doc[]} docs - docs to be searched through recursively
      * @param {number, Doc => void} func - function to be called on each doc
@@ -213,74 +186,10 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
     @action
     searchCollection(query: string) {
         this._selectedResult = undefined;
-        this._results = SearchBox.staticSearchCollection(CollectionDockingView.Instance?.rootDoc, query);
+        this._results = SearchUtil.SearchCollection(CollectionDockingView.Instance?.rootDoc, query);
 
         this.computePageRanks();
     }
-    @action
-    static staticSearchCollection(rootDoc: Opt<Doc>, query: string) {
-        const blockedTypes = [DocumentType.PRESELEMENT, DocumentType.CONFIG, DocumentType.KVP, DocumentType.SEARCH, DocumentType.FONTICON, DocumentType.BUTTON, DocumentType.SCRIPTING];
-        const blockedKeys = [
-            'x',
-            'y',
-            'proto',
-            'width',
-            'layout_autoHeight',
-            'acl-Override',
-            'acl-Guest',
-            'embedContainer',
-            'zIndex',
-            'height',
-            'text_scrollHeight',
-            'text_height',
-            'cloneFieldFilter',
-            'isDataDoc',
-            'text_annotations',
-            'dragFactory_count',
-            'text_noTemplate',
-            'proto_embeddings',
-            'isSystem',
-            'layout_fieldKey',
-            'isBaseProto',
-            'xMargin',
-            'yMargin',
-            'links',
-            'layout',
-            'layout_keyValue',
-            'layout_fitWidth',
-            'type_collection',
-            'title_custom',
-            'freeform_panX',
-            'freeform_panY',
-            'freeform_scale',
-        ];
-        query = query.toLowerCase();
-
-        const results = new Map<Doc, string[]>();
-        if (rootDoc) {
-            const docs = DocListCast(rootDoc[Doc.LayoutFieldKey(rootDoc)]);
-            const docIDs: String[] = [];
-            SearchBox.foreachRecursiveDoc(docs, (depth: number, doc: Doc) => {
-                const dtype = StrCast(doc.type) as DocumentType;
-                if (dtype && !blockedTypes.includes(dtype) && !docIDs.includes(doc[Id]) && depth >= 0) {
-                    const hlights = new Set<string>();
-                    SearchBox.documentKeys(doc).forEach(
-                        key =>
-                            Field.toString(doc[key] as Field)
-                                .toLowerCase()
-                                .includes(query) && hlights.add(key)
-                    );
-                    blockedKeys.forEach(key => hlights.delete(key));
-
-                    if (Array.from(hlights.keys()).length > 0) {
-                        results.set(doc, Array.from(hlights.keys()));
-                    }
-                }
-                docIDs.push(doc[Id]);
-            });
-        }
-        return results;
-    }
 
     /**
      * This method initializes the page rank of every document to the reciprocal
@@ -373,17 +282,6 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
         }
     }
 
-    /**
-     * @param {Doc} doc - doc for which keys are returned
-     *
-     * This method returns a list of a document doc's keys.
-     */
-    static documentKeys(doc: Doc) {
-        const keys: { [key: string]: boolean } = {};
-        Doc.GetAllPrototypes(doc).map(proto => Object.keys(proto).forEach(key => (keys[key] = false)));
-        return Array.from(Object.keys(keys));
-    }
-
     /**
      * This method submits a search with the _searchString as its query and updates
      * the results array accordingly.
@@ -518,7 +416,7 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
                             className={className}>
                             <div className="searchBox-result-title">{title as string}</div>
                             <div className="searchBox-result-type">{formattedType}</div>
-                            <div className="searchBox-result-keys" style={{ color: SettingsManager.Instance.userVariantColor }}>
+                            <div className="searchBox-result-keys" style={{ color: SettingsManager.userVariantColor }}>
                                 {result[1].join(', ')}
                             </div>
                         </div>
@@ -530,7 +428,7 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
         const recommendationsJSX: JSX.Element[] = this._recommendations.map(props => <Recommendation {...props} />);
 
         return (
-            <div className="searchBox-container" style={{ pointerEvents: 'all', color: SettingsManager.Instance.userColor, background: SettingsManager.Instance.userBackgroundColor }}>
+            <div className="searchBox-container" style={{ pointerEvents: 'all', color: SettingsManager.userColor, background: SettingsManager.userBackgroundColor }}>
                 <div className="searchBox-bar">
                     {isLinkSearch ? null : (
                         <select name="type" id="searchBox-type" className="searchBox-type" onChange={this.onSelectChange}>
diff --git a/src/client/views/topbar/TopBar.tsx b/src/client/views/topbar/TopBar.tsx
index c194ede32..a2f9de9ab 100644
--- a/src/client/views/topbar/TopBar.tsx
+++ b/src/client/views/topbar/TopBar.tsx
@@ -1,13 +1,14 @@
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { Button, IconButton, Size, Type, isDark } from 'browndash-components';
+import { Button, IconButton, isDark, Size, Type } from 'browndash-components';
 import { action, computed, observable, reaction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
-import { FaBug, FaCamera, FaStamp } from 'react-icons/fa';
+import { FaBug, FaCamera } from 'react-icons/fa';
 import { Doc, DocListCast } from '../../../fields/Doc';
 import { AclAdmin, DashVersion } from '../../../fields/DocSymbols';
 import { StrCast } from '../../../fields/Types';
 import { GetEffectiveAcl } from '../../../fields/util';
+import { CurrentUserUtils } from '../../util/CurrentUserUtils';
 import { DocumentManager } from '../../util/DocumentManager';
 import { PingManager } from '../../util/PingManager';
 import { ReportManager } from '../../util/reportManager/ReportManager';
@@ -15,13 +16,12 @@ import { ServerStats } from '../../util/ServerStats';
 import { SettingsManager } from '../../util/SettingsManager';
 import { SharingManager } from '../../util/SharingManager';
 import { UndoManager } from '../../util/UndoManager';
+import { CollectionDockingView } from '../collections/CollectionDockingView';
 import { ContextMenu } from '../ContextMenu';
 import { DashboardView } from '../DashboardView';
-import { MainView } from '../MainView';
-import { CollectionDockingView } from '../collections/CollectionDockingView';
 import { Colors } from '../global/globalEnums';
+import { DocumentView } from '../nodes/DocumentView';
 import './TopBar.scss';
-import { CurrentUserUtils } from '../../util/CurrentUserUtils';
 
 /**
  * ABOUT: This is the topbar in Dash, which included the current Dashboard as well as access to information on the user
@@ -43,7 +43,7 @@ export class TopBar extends React.Component {
         return StrCast(Doc.UserDoc().userVariantColor, Colors.MEDIUM_BLUE);
     }
     @computed get backgroundColor() {
-        return PingManager.Instance.IsBeating ? SettingsManager.Instance.userBackgroundColor : Colors.MEDIUM_GRAY;
+        return PingManager.Instance.IsBeating ? SettingsManager.userBackgroundColor : Colors.MEDIUM_GRAY;
     }
 
     @observable happyHeart: boolean = PingManager.Instance.IsBeating;
@@ -76,9 +76,7 @@ export class TopBar extends React.Component {
                         <span style={{ color: isDark(this.backgroundColor) ? Colors.LIGHT_BLUE : Colors.MEDIUM_BLUE, fontWeight: 500 }}>dash</span>
                     </div>
                 )}
-                {Doc.ActiveDashboard && (
-                    <Button text="Explore" tooltip="Browsing mode for directly navigating to documents" size={Size.SMALL} color={this.color} onClick={action(() => (MainView.Instance._exploreMode = !MainView.Instance._exploreMode))} />
-                )}
+                {Doc.ActiveDashboard && <Button text="Explore" tooltip="Browsing mode for directly navigating to documents" size={Size.SMALL} color={this.color} onClick={action(() => (DocumentView.ExploreMode = !DocumentView.ExploreMode))} />}
             </div>
         );
     }
diff --git a/src/client/views/webcam/DashWebRTCVideo.tsx b/src/client/views/webcam/DashWebRTCVideo.tsx
index 02e44a793..524492226 100644
--- a/src/client/views/webcam/DashWebRTCVideo.tsx
+++ b/src/client/views/webcam/DashWebRTCVideo.tsx
@@ -6,8 +6,8 @@ import { observer } from 'mobx-react';
 import { Doc } from '../../../fields/Doc';
 import { InkTool } from '../../../fields/InkField';
 import '../../views/nodes/WebBox.scss';
-import { DocumentDecorations } from '../DocumentDecorations';
 import { CollectionFreeFormDocumentViewProps } from '../nodes/CollectionFreeFormDocumentView';
+import { DocumentView } from '../nodes/DocumentView';
 import { FieldView, FieldViewProps } from '../nodes/FieldView';
 import './DashWebRTCVideo.scss';
 import { hangup, initialize, refreshVideos } from './WebCamLogic';
@@ -71,8 +71,8 @@ export class DashWebRTCVideo extends React.Component<CollectionFreeFormDocumentV
             </div>
         );
 
-        const frozen = !this.props.isSelected() || DocumentDecorations.Instance.Interacting;
-        const classname = 'webBox-cont' + (this.props.isSelected() && Doc.ActiveTool === InkTool.None && !DocumentDecorations.Instance.Interacting ? '-interactive' : '');
+        const frozen = !this.props.isSelected() || DocumentView.Interacting;
+        const classname = 'webBox-cont' + (this.props.isSelected() && Doc.ActiveTool === InkTool.None && !DocumentView.Interacting ? '-interactive' : '');
 
         return (
             <>
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 4ad38e7fc..f17e10d9e 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -47,7 +47,7 @@ import { FieldId, RefField } from './RefField';
 import { RichTextField } from './RichTextField';
 import { listSpec } from './Schema';
 import { ComputedField, ScriptField } from './ScriptField';
-import { Cast, DocCast, FieldValue, NumCast, StrCast, ToConstructor } from './Types';
+import { BoolCast, Cast, DocCast, FieldValue, NumCast, StrCast, ToConstructor } from './Types';
 import { AudioField, CsvField, ImageField, PdfField, VideoField, WebField } from './URLField';
 import { containedFieldChangedHandler, deleteProperty, GetEffectiveAcl, getField, getter, makeEditable, makeReadOnly, normalizeEmail, setter, SharingPermissions } from './util';
 import JSZip = require('jszip');
@@ -156,7 +156,26 @@ export function updateCachedAcls(doc: Doc) {
 @scriptingGlobal
 @Deserializable('Doc', updateCachedAcls, ['id'])
 export class Doc extends RefField {
-    @observable public static CurrentlyLoading: Doc[];
+    @observable public static RecordingEvent = 0;
+
+    // this isn't really used at the moment, but is intended to indicate whether ink stroke are passed through a gesture recognizer
+    static GetRecognizeGestures() {
+        return BoolCast(Doc.UserDoc()._recognizeGestures);
+    }
+    static SetRecognizeGestures(show: boolean) {
+        Doc.UserDoc()._recognizeGestures = show;
+    }
+
+    //
+    // This controls whether fontIconButtons will display labels under their icons or not
+    //
+    static GetShowIconLabels() {
+        return BoolCast(Doc.UserDoc()._showLabel);
+    }
+    static SetShowIconLabels(show: boolean) {
+        Doc.UserDoc()._showLabel = show;
+    }
+    @observable public static CurrentlyLoading: Doc[] = []; // this assignment doesn't work. the actual assignment happens in DocumentManager's constructor
     // removes from currently loading display
     @action
     public static removeCurrentlyLoading(doc: Doc) {
@@ -169,9 +188,6 @@ export class Doc extends RefField {
     // adds doc to currently loading display
     @action
     public static addCurrentlyLoading(doc: Doc) {
-        if (!Doc.CurrentlyLoading) {
-            Doc.CurrentlyLoading = [];
-        }
         if (Doc.CurrentlyLoading.indexOf(doc) === -1) {
             Doc.CurrentlyLoading.push(doc);
         }
diff --git a/src/fields/RichTextUtils.ts b/src/fields/RichTextUtils.ts
index 24cd078f2..5ecf25e08 100644
--- a/src/fields/RichTextUtils.ts
+++ b/src/fields/RichTextUtils.ts
@@ -2,20 +2,20 @@ import { AssertionError } from 'assert';
 import { docs_v1 } from 'googleapis';
 import { Fragment, Mark, Node } from 'prosemirror-model';
 import { sinkListItem } from 'prosemirror-schema-list';
-import { Utils, DashColor } from '../Utils';
-import { Docs, DocUtils } from '../client/documents/Documents';
-import { schema } from '../client/views/nodes/formattedText/schema_rts';
+import { EditorState, TextSelection, Transaction } from 'prosemirror-state';
+import { GoogleApiClientUtils } from '../client/apis/google_docs/GoogleApiClientUtils';
 import { GooglePhotos } from '../client/apis/google_docs/GooglePhotosClientUtils';
 import { DocServer } from '../client/DocServer';
+import { Docs, DocUtils } from '../client/documents/Documents';
 import { Networking } from '../client/Network';
 import { FormattedTextBox } from '../client/views/nodes/formattedText/FormattedTextBox';
+import { schema } from '../client/views/nodes/formattedText/schema_rts';
+import { DashColor, Utils } from '../Utils';
 import { Doc, Opt } from './Doc';
 import { Id } from './FieldSymbols';
 import { RichTextField } from './RichTextField';
 import { Cast, StrCast } from './Types';
 import Color = require('color');
-import { EditorState, TextSelection, Transaction } from 'prosemirror-state';
-import { GoogleApiClientUtils } from '../client/apis/google_docs/GoogleApiClientUtils';
 
 export namespace RichTextUtils {
     const delimiter = '\n';
-- 
cgit v1.2.3-70-g09d2


From 5651f5428f8464ae0f131c73601b69aba11dff98 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 31 Aug 2023 12:36:33 -0400
Subject: fixed properties view text colors

---
 src/client/views/MainView.tsx             | 2 +-
 src/client/views/collections/TreeView.tsx | 3 ---
 src/client/views/nodes/trails/PresBox.tsx | 2 +-
 3 files changed, 2 insertions(+), 5 deletions(-)

(limited to 'src/client/views/collections/TreeView.tsx')

diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 01a26559c..7ae9a374d 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -809,7 +809,7 @@ export class MainView extends React.Component {
                                 <FontAwesomeIcon icon={this.propertiesWidth() < 10 ? 'chevron-left' : 'chevron-right'} color={SettingsManager.userColor} size="sm" />
                             </div>
                         )}
-                        <div className="properties-container" style={{ width: this.propertiesWidth() }}>
+                        <div className="properties-container" style={{ width: this.propertiesWidth(), color: SettingsManager.userColor }}>
                             {this.propertiesWidth() < 10 ? null : <PropertiesView styleProvider={DefaultStyleProvider} addDocTab={DocumentViewInternal.addDocTabFunc} width={this.propertiesWidth()} height={this.propertiesHeight()} />}
                         </div>
                     </div>
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 4f9310434..8dd1c8ee8 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -227,7 +227,6 @@ export class TreeView extends React.Component<TreeViewProps> {
     recurToggle = (childList: Doc[]) => {
         if (childList.length > 0) {
             childList.forEach(child => {
-                console.log(child);
                 child.runProcess = !!!child.runProcess;
                 TreeView.ToggleChildrenRun.get(child)?.();
             });
@@ -265,8 +264,6 @@ export class TreeView extends React.Component<TreeViewProps> {
         this._editTitleScript = Doc.IsSystem(this.props.document) ? () => TreeView._openLevelScript! : () => TreeView._openTitleScript!;
 
         // set for child processing highligting
-        // this.dataDoc.testing = 'testing';
-        console.log(this.doc, this.dataDoc, this.childDocs);
         this.dataDoc.hasChildren = this.childDocs.length > 0;
         // this.dataDoc.children = this.childDocs;
         TreeView.ToggleChildrenRun.set(this.doc, () => {
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index 7bb1b80a3..92c130ea1 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -1691,7 +1691,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
             </div>
         );
         const presDirection = (direction: PresEffectDirection, icon: string, gridColumn: number, gridRow: number, opts: object) => {
-            const color = activeItem.presentation_effectDirection === direction || (direction === PresEffectDirection.Center && !activeItem.presentation_effectDirection) ? Colors.LIGHT_BLUE : 'black';
+            const color = activeItem.presentation_effectDirection === direction || (direction === PresEffectDirection.Center && !activeItem.presentation_effectDirection) ? SettingsManager.userVariantColor : SettingsManager.userColor;
             return (
                 <Tooltip title={<div className="dash-tooltip">{direction}</div>}>
                     <div
-- 
cgit v1.2.3-70-g09d2


From ff458c1cc2619803b8f8ba6e1a2b713b8d3bafe7 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 5 Sep 2023 11:29:05 -0400
Subject: changed tree view drag behavior

---
 src/client/views/collections/TreeView.tsx | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

(limited to 'src/client/views/collections/TreeView.tsx')

diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 8dd1c8ee8..f1268119e 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -332,7 +332,7 @@ export class TreeView extends React.Component<TreeViewProps> {
         const pt = [e.clientX, e.clientY];
         const rect = this._header.current!.getBoundingClientRect();
         const before = pt[1] < rect.top + rect.height / 2;
-        const inside = pt[0] > Math.min(rect.left + 75, rect.left + rect.width * 0.75) || (!before && this.treeViewOpen && this.childDocs?.length);
+        const inside = pt[0] > rect.left + rect.width * 0.33 || (!before && this.treeViewOpen && this.childDocs?.length);
         this._header.current!.className = 'treeView-header';
         if (!this.props.treeView.outlineMode || DragManager.DocDragData?.treeViewDoc === this.props.treeView.rootDoc) {
             if (inside) this._header.current!.className += ' treeView-header-inside';
@@ -392,7 +392,7 @@ export class TreeView extends React.Component<TreeViewProps> {
         if (!this._header.current) return false;
         const rect = this._header.current.getBoundingClientRect();
         const before = pt[1] < rect.top + rect.height / 2;
-        const inside = this.props.treeView.fileSysMode && !this.doc.isFolder ? false : pt[0] > Math.min(rect.left + 75, rect.left + rect.width * 0.75) || (!before && this.treeViewOpen && this.childDocs?.length ? true : false);
+        const inside = this.props.treeView.fileSysMode && !this.doc.isFolder ? false : pt[0] > rect.left + rect.width * 0.33 || (!before && this.treeViewOpen && this.childDocs?.length ? true : false);
         if (de.complete.linkDragData) {
             const sourceDoc = de.complete.linkDragData.linkSourceGetAnchor();
             const destDoc = this.doc;
@@ -1140,7 +1140,7 @@ export class TreeView extends React.Component<TreeViewProps> {
         const pt = [de.clientX, de.clientY];
         const rect = this._header.current!.getBoundingClientRect();
         const before = pt[1] < rect.top + rect.height / 2;
-        const inside = this.props.treeView.fileSysMode && !this.doc.isFolder ? false : pt[0] > Math.min(rect.left + 75, rect.left + rect.width * 0.75) || (!before && this.treeViewOpen && this.childDocs?.length ? true : false);
+        const inside = this.props.treeView.fileSysMode && !this.doc.isFolder ? false : pt[0] > rect.left + rect.width * 0.33 || (!before && this.treeViewOpen && this.childDocs?.length ? true : false);
 
         const docs = this.props.treeView.onTreeDrop(de, (docs: Doc[]) => this.dropDocuments(docs, before, inside, 'copy', undefined, undefined, false));
     };
-- 
cgit v1.2.3-70-g09d2


From 3a048ae3acbbf63611bfbb7cded772fc3decd526 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 11 Sep 2023 22:58:56 -0400
Subject: usercolor cleanup

---
 src/client/util/RTFMarkup.tsx                      |  2 +-
 src/client/views/AntimodeMenu.tsx                  |  7 +-
 src/client/views/ContextMenu.tsx                   |  7 +-
 src/client/views/PropertiesButtons.tsx             |  5 +-
 src/client/views/PropertiesSection.tsx             |  7 +-
 src/client/views/PropertiesView.tsx                | 21 +++---
 src/client/views/StyleProvider.tsx                 |  8 +--
 src/client/views/collections/CollectionMenu.tsx    |  6 +-
 .../views/collections/CollectionStackingView.tsx   |  3 +-
 src/client/views/collections/TreeView.tsx          |  5 +-
 .../collectionFreeForm/MarqueeOptionsMenu.tsx      | 38 ++---------
 src/client/views/nodes/MapBox/MapAnchorMenu.tsx    | 75 +++++++++++-----------
 src/client/views/nodes/MapBox/MapBox.tsx           |  3 +-
 13 files changed, 82 insertions(+), 105 deletions(-)

(limited to 'src/client/views/collections/TreeView.tsx')

diff --git a/src/client/util/RTFMarkup.tsx b/src/client/util/RTFMarkup.tsx
index 9dd14a3c3..c8940194c 100644
--- a/src/client/util/RTFMarkup.tsx
+++ b/src/client/util/RTFMarkup.tsx
@@ -137,7 +137,7 @@ export class RTFMarkup extends React.Component<{}> {
     render() {
         return (
             <MainViewModal
-                dialogueBoxStyle={{ backgroundColor: StrCast(Doc.UserDoc().userBackgroundColor), color: StrCast(Doc.UserDoc().userColor), padding: '16px' }}
+                dialogueBoxStyle={{ backgroundColor: SettingsManager.userBackgroundColor, color: SettingsManager.userColor, padding: '16px' }}
                 contents={this.cheatSheet}
                 isDisplayed={this.isOpen}
                 interactive={true}
diff --git a/src/client/views/AntimodeMenu.tsx b/src/client/views/AntimodeMenu.tsx
index c41ea7053..16e76694d 100644
--- a/src/client/views/AntimodeMenu.tsx
+++ b/src/client/views/AntimodeMenu.tsx
@@ -3,6 +3,7 @@ import { observable, action, runInAction } from 'mobx';
 import './AntimodeMenu.scss';
 import { StrCast } from '../../fields/Types';
 import { Doc } from '../../fields/Doc';
+import { SettingsManager } from '../util/SettingsManager';
 export interface AntimodeMenuProps {}
 
 /**
@@ -150,7 +151,7 @@ export abstract class AntimodeMenu<T extends AntimodeMenuProps> extends React.Co
                     left: this._left,
                     top: this._top,
                     opacity: this._opacity,
-                    background: StrCast(Doc.UserDoc().userBackgroundColor),
+                    background: SettingsManager.userBackgroundColor,
                     transitionProperty: this._transitionProperty,
                     transitionDuration: this._transitionDuration,
                     transitionDelay: this._transitionDelay,
@@ -176,7 +177,7 @@ export abstract class AntimodeMenu<T extends AntimodeMenuProps> extends React.Co
                     height: 'inherit',
                     width: 200,
                     opacity: this._opacity,
-                    background: StrCast(Doc.UserDoc().userBackgroundColor),
+                    background: SettingsManager.userBackgroundColor,
                     transitionProperty: this._transitionProperty,
                     transitionDuration: this._transitionDuration,
                     transitionDelay: this._transitionDelay,
@@ -199,7 +200,7 @@ export abstract class AntimodeMenu<T extends AntimodeMenuProps> extends React.Co
                     left: this._left,
                     top: this._top,
                     opacity: this._opacity,
-                    background: StrCast(Doc.UserDoc().userBackgroundColor),
+                    background: SettingsManager.userBackgroundColor,
                     transitionProperty: this._transitionProperty,
                     transitionDuration: this._transitionDuration,
                     transitionDelay: this._transitionDelay,
diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx
index 8412a9aae..adefc7e9c 100644
--- a/src/client/views/ContextMenu.tsx
+++ b/src/client/views/ContextMenu.tsx
@@ -7,6 +7,7 @@ import { ContextMenuItem, ContextMenuProps, OriginalMenuProps } from './ContextM
 import { Utils } from '../../Utils';
 import { StrCast } from '../../fields/Types';
 import { Doc } from '../../fields/Doc';
+import { SettingsManager } from '../util/SettingsManager';
 
 @observer
 export class ContextMenu extends React.Component {
@@ -195,7 +196,7 @@ export class ContextMenu extends React.Component {
                 <div
                     className="contextMenu-group"
                     style={{
-                        background: StrCast(Doc.UserDoc().userVariantColor),
+                        background: StrCast(SettingsManager.userVariantColor),
                     }}>
                     <div className="contextMenu-description">{value.join(' -> ')}</div>
                 </div>
@@ -222,8 +223,8 @@ export class ContextMenu extends React.Component {
                 style={{
                     left: this.pageX,
                     ...(this._yRelativeToTop ? { top: this.pageY } : { bottom: this.pageY }),
-                    background: StrCast(Doc.UserDoc().userBackgroundColor),
-                    color: StrCast(Doc.UserDoc().userColor),
+                    background: SettingsManager.userBackgroundColor,
+                    color: SettingsManager.userColor,
                 }}>
                 {!this.itemsNeedSearch ? null : (
                     <span className={'search-icon'}>
diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx
index 8b2b77aca..40d42a4de 100644
--- a/src/client/views/PropertiesButtons.tsx
+++ b/src/client/views/PropertiesButtons.tsx
@@ -32,6 +32,7 @@ import { TfiBarChart } from 'react-icons/tfi';
 import { CiGrid31 } from 'react-icons/ci';
 import { RxWidth } from 'react-icons/rx';
 import { Dropdown, DropdownType, IListItemProps, Toggle, ToggleType, Type } from 'browndash-components';
+import { SettingsManager } from '../util/SettingsManager';
 
 enum UtilityButtonState {
     Default,
@@ -57,7 +58,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
             <Toggle
                 toggleStatus={BoolCast(targetDoc[property])}
                 text={label(targetDoc?.[property])}
-                color={StrCast(Doc.UserDoc().userColor)}
+                color={SettingsManager.userColor}
                 icon={icon(targetDoc?.[property] as any)}
                 iconPlacement={'left'}
                 align={'flex-start'}
@@ -380,7 +381,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
                 selectedVal={this.onClickVal}
                 setSelectedVal={val => this.handleOptionChange(val as string)}
                 title={'Choose onClick behaviour'}
-                color={StrCast(Doc.UserDoc().userColor)}
+                color={SettingsManager.userColor}
                 dropdownType={DropdownType.SELECT}
                 type={Type.SEC}
                 fillWidth
diff --git a/src/client/views/PropertiesSection.tsx b/src/client/views/PropertiesSection.tsx
index 0e7cd7e92..bd586b2f9 100644
--- a/src/client/views/PropertiesSection.tsx
+++ b/src/client/views/PropertiesSection.tsx
@@ -5,6 +5,7 @@ import { observer } from 'mobx-react';
 import './PropertiesSection.scss';
 import { Doc } from '../../fields/Doc';
 import { StrCast } from '../../fields/Types';
+import { SettingsManager } from '../util/SettingsManager';
 
 export interface PropertiesSectionProps {
     title: string;
@@ -19,15 +20,15 @@ export interface PropertiesSectionProps {
 @observer
 export class PropertiesSection extends React.Component<PropertiesSectionProps> {
     @computed get color() {
-        return StrCast(Doc.UserDoc().userColor);
+        return SettingsManager.userColor;
     }
 
     @computed get backgroundColor() {
-        return StrCast(Doc.UserDoc().userBackgroundColor);
+        return SettingsManager.userBackgroundColor;
     }
 
     @computed get variantColor() {
-        return StrCast(Doc.UserDoc().userVariantColor);
+        return SettingsManager.userVariantColor;
     }
 
     @observable isDouble: boolean = false;
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index b25ac7903..699aafe80 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -368,7 +368,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                 <IconButton
                     icon={<FontAwesomeIcon icon={'ellipsis-h'} />}
                     size={Size.XSMALL}
-                    color={StrCast(Doc.UserDoc().userColor)}
+                    color={SettingsManager.userColor}
                     onClick={action(() => {
                         if (this.selectedDocumentView || this.selectedDoc) {
                             SharingManager.Instance.open(this.selectedDocumentView?.props.Document === this.selectedDoc ? this.selectedDocumentView : undefined, this.selectedDoc);
@@ -518,7 +518,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                 <div>
                     <br></br> Individuals with Access to this Document
                 </div>
-                <div className="propertiesView-sharingTable" style={{ background: StrCast(Doc.UserDoc().userBackgroundColor), color: StrCast(Doc.UserDoc().userColor) }}>
+                <div className="propertiesView-sharingTable" style={{ background: SettingsManager.userBackgroundColor, color: SettingsManager.userColor }}>
                     {<div> {individualTableEntries}</div>}
                 </div>
                 {groupTableEntries.length > 0 ? (
@@ -526,7 +526,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                         <div>
                             <br></br> Groups with Access to this Document
                         </div>
-                        <div className="propertiesView-sharingTable" style={{ background: StrCast(Doc.UserDoc().userBackgroundColor), color: StrCast(Doc.UserDoc().userColor) }}>
+                        <div className="propertiesView-sharingTable" style={{ background: SettingsManager.userBackgroundColor, color: SettingsManager.userColor }}>
                             {<div> {groupTableEntries}</div>}
                         </div>
                     </div>
@@ -546,15 +546,15 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     toggleCheckbox = () => (this.layoutFields = !this.layoutFields);
 
     @computed get color() {
-        return StrCast(Doc.UserDoc().userColor);
+        return SettingsManager.userColor;
     }
 
     @computed get backgroundColor() {
-        return StrCast(Doc.UserDoc().userBackgroundColor);
+        return SettingsManager.userBackgroundColor;
     }
 
     @computed get variantColor() {
-        return StrCast(Doc.UserDoc().userVariantColor);
+        return SettingsManager.userVariantColor;
     }
 
     @computed get editableTitle() {
@@ -585,8 +585,6 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     }
 
     @computed get currentType() {
-        // console.log("current type " + this.selectedDoc?.type)
-
         const documentType = StrCast(this.selectedDoc?.type);
         var currentType: string = documentType;
         var capitalizedDocType = Utils.cleanDocumentType(currentType as DocumentType);
@@ -610,9 +608,8 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         if (iconName) {
             const Icon = Icons[iconName as keyof typeof Icons];
             return <Icon />;
-        } else {
-            return <Icons.BsFillCollectionFill />;
         }
+        return <Icons.BsFillCollectionFill />;
     }
 
     @undoBatch
@@ -1683,8 +1680,8 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                     <div
                         className="propertiesView"
                         style={{
-                            background: StrCast(Doc.UserDoc().userBackgroundColor),
-                            color: StrCast(Doc.UserDoc().userColor),
+                            background: SettingsManager.userBackgroundColor,
+                            color: SettingsManager.userColor,
                             width: this.props.width,
                             minWidth: this.props.width,
                         }}>
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index 8a5ad3139..85aa5ad83 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -162,8 +162,8 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
             );
         case StyleProp.Color:
             if (DocumentView.LastPressedSidebarBtn === doc) return SettingsManager.userBackgroundColor;
-            if (Doc.IsSystem(doc!)) return StrCast(Doc.UserDoc().userColor)
-            if (doc?.type === DocumentType.FONTICON) return Doc.UserDoc().userColor;
+            if (Doc.IsSystem(doc!)) return SettingsManager.userColor;
+            if (doc?.type === DocumentType.FONTICON) return SettingsManager.userColor;
             const docColor: Opt<string> = StrCast(doc?.[fieldKey + 'color'], StrCast(doc?._color));
             if (docColor) return docColor;
             const docView = props?.DocumentView?.();
@@ -196,7 +196,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
                 ? 15
                 : 0;
         case StyleProp.BackgroundColor: {
-            if (DocumentView.LastPressedSidebarBtn === doc) return StrCast(Doc.UserDoc().userColor); // hack to indicate active menu panel item
+            if (DocumentView.LastPressedSidebarBtn === doc) return SettingsManager.userColor; // hack to indicate active menu panel item
             let docColor: Opt<string> = StrCast(doc?.[fieldKey + '_backgroundColor'], StrCast(doc?._backgroundColor, isCaption ? 'rgba(0,0,0,0.4)' : ''));
             // prettier-ignore
             switch (doc?.type) {
@@ -350,7 +350,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
 }
 
 export function DashboardToggleButton(doc: Doc, field: string, onIcon: IconProp, offIcon: IconProp, clickFunc?: () => void) {
-    const color = StrCast(Doc.UserDoc().userColor);
+    const color = SettingsManager.userColor;
     return (
         <IconButton
             size={Size.XSMALL}
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 78ab0797b..ec9d86c1a 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -158,7 +158,7 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> {
                 <Toggle
                     toggleType={ToggleType.BUTTON}
                     type={Type.PRIM}
-                    color={StrCast(Doc.UserDoc().userColor)}
+                    color={SettingsManager.userColor}
                     onClick={this.toggleTopBar}
                     toggleStatus={SettingsManager.headerBarHeight > 0}
                     icon={<FontAwesomeIcon icon={headerIcon} size="lg" />}
@@ -167,7 +167,7 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> {
                 <Toggle
                     toggleType={ToggleType.BUTTON}
                     type={Type.PRIM}
-                    color={StrCast(Doc.UserDoc().userColor)}
+                    color={SettingsManager.userColor}
                     onClick={this.toggleProperties}
                     toggleStatus={SettingsManager.propertiesWidth > 0}
                     icon={<FontAwesomeIcon icon={propIcon} size="lg" />}
@@ -183,7 +183,7 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> {
                 className="collectionMenu-container"
                 style={{
                     background: SettingsManager.userBackgroundColor,
-                    // borderColor: StrCast(Doc.UserDoc().userColor)
+                    // borderColor: SettingsManager.userColor
                 }}>
                 {this.contMenuButtons}
                 {hardCodedButtons}
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index e4a0d6dad..9ba4cb6cf 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -31,6 +31,7 @@ import { CollectionMasonryViewFieldRow } from './CollectionMasonryViewFieldRow';
 import './CollectionStackingView.scss';
 import { CollectionStackingViewFieldColumn } from './CollectionStackingViewFieldColumn';
 import { CollectionSubView } from './CollectionSubView';
+import { SettingsManager } from '../../util/SettingsManager';
 const _global = (window /* browser */ || global) /* node */ as any;
 
 export type collectionStackingViewProps = {
@@ -426,7 +427,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
                 className="collectionStackingView-columnDragger"
                 onPointerDown={this.columnDividerDown}
                 ref={this._draggerRef}
-                style={{ cursor: this._cursor, color: StrCast(Doc.UserDoc().userColor), left: `${this.columnWidth + this.xMargin}px`, top: `${Math.max(0, this.yMargin - 9)}px` }}>
+                style={{ cursor: this._cursor, color: SettingsManager.userColor, left: `${this.columnWidth + this.xMargin}px`, top: `${Math.max(0, this.yMargin - 9)}px` }}>
                 <FontAwesomeIcon icon={'arrows-alt-h'} />
             </div>
         );
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index f1268119e..71e9f4dfa 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -36,6 +36,7 @@ import './TreeView.scss';
 import React = require('react');
 import { IconButton, Size } from 'browndash-components';
 import { TreeSort } from './TreeSort';
+import { SettingsManager } from '../../util/SettingsManager';
 
 export interface TreeViewProps {
     treeView: CollectionTreeView;
@@ -736,7 +737,7 @@ export class TreeView extends React.Component<TreeViewProps> {
     @computed get renderBullet() {
         TraceMobx();
         const iconType = this.props.treeView.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.TreeViewIcon + (this.treeViewOpen ? ':open' : !this.childDocs.length ? ':empty' : '')) || 'question';
-        const color = StrCast(Doc.UserDoc().userColor);
+        const color = SettingsManager.userColor;
         const checked = this.onCheckedClick ? this.doc.treeView_Checked ?? 'unchecked' : undefined;
         return (
             <div
@@ -796,7 +797,7 @@ export class TreeView extends React.Component<TreeViewProps> {
     @observable headerEleWidth = 0;
     @computed get titleButtons() {
         const customHeaderButtons = this.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.Decorations);
-        const color = StrCast(Doc.UserDoc().userColor);
+        const color = SettingsManager.userColor;
         return this.props.treeViewHideHeaderFields() || this.doc.treeView_HideHeaderFields ? null : (
             <>
                 {customHeaderButtons} {/* e.g.,. hide button is set by dashboardStyleProvider */}
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx
index 71900c63f..607f9fb95 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx
@@ -8,6 +8,7 @@ import { IconButton } from 'browndash-components';
 import { StrCast } from '../../../../fields/Types';
 import { Doc } from '../../../../fields/Doc';
 import { computed } from 'mobx';
+import { SettingsManager } from '../../../util/SettingsManager';
 
 @observer
 export class MarqueeOptionsMenu extends AntimodeMenu<AntimodeMenuProps> {
@@ -27,43 +28,18 @@ export class MarqueeOptionsMenu extends AntimodeMenu<AntimodeMenuProps> {
     }
 
     @computed get userColor() {
-        return StrCast(Doc.UserDoc().userColor)
+        return SettingsManager.userColor;
     }
 
     render() {
         const presPinWithViewIcon = <img src="/assets/pinWithView.png" style={{ width: 19 }} />;
         const buttons = (
             <>
-                <IconButton 
-                    tooltip={"Create a Collection"}
-                    onPointerDown={this.createCollection}
-                    icon={<FontAwesomeIcon icon="object-group"/>}
-                    color={this.userColor}
-                />
-                <IconButton 
-                    tooltip={"Create a Grouping"}
-                    onPointerDown={e => this.createCollection(e, true)}
-                    icon={<FontAwesomeIcon icon="layer-group"/>}
-                    color={this.userColor}
-                />
-                <IconButton 
-                    tooltip={"Summarize Documents"}
-                    onPointerDown={this.summarize}
-                    icon={<FontAwesomeIcon icon="compress-arrows-alt"/>}
-                    color={this.userColor}
-                />
-                <IconButton 
-                    tooltip={"Delete Documents"}
-                    onPointerDown={this.delete}
-                    icon={<FontAwesomeIcon icon="trash-alt"/>}
-                    color={this.userColor}
-                />
-                <IconButton 
-                    tooltip={"Pin selected region"}
-                    onPointerDown={this.pinWithView}
-                    icon={<FontAwesomeIcon icon="map-pin"/>}
-                    color={this.userColor}
-                />
+                <IconButton tooltip={'Create a Collection'} onPointerDown={this.createCollection} icon={<FontAwesomeIcon icon="object-group" />} color={this.userColor} />
+                <IconButton tooltip={'Create a Grouping'} onPointerDown={e => this.createCollection(e, true)} icon={<FontAwesomeIcon icon="layer-group" />} color={this.userColor} />
+                <IconButton tooltip={'Summarize Documents'} onPointerDown={this.summarize} icon={<FontAwesomeIcon icon="compress-arrows-alt" />} color={this.userColor} />
+                <IconButton tooltip={'Delete Documents'} onPointerDown={this.delete} icon={<FontAwesomeIcon icon="trash-alt" />} color={this.userColor} />
+                <IconButton tooltip={'Pin selected region'} onPointerDown={this.pinWithView} icon={<FontAwesomeIcon icon="map-pin" />} color={this.userColor} />
             </>
         );
         return this.getElement(buttons);
diff --git a/src/client/views/nodes/MapBox/MapAnchorMenu.tsx b/src/client/views/nodes/MapBox/MapAnchorMenu.tsx
index f731763af..f0827936b 100644
--- a/src/client/views/nodes/MapBox/MapAnchorMenu.tsx
+++ b/src/client/views/nodes/MapBox/MapAnchorMenu.tsx
@@ -6,7 +6,7 @@ import { ColorState } from 'react-color';
 import { Doc, Opt } from '../../../../fields/Doc';
 import { returnFalse, setupMoveUpEvents, unimplementedFunction, Utils } from '../../../../Utils';
 import { SelectionManager } from '../../../util/SelectionManager';
-import { AntimodeMenu, AntimodeMenuProps } from "../../AntimodeMenu"
+import { AntimodeMenu, AntimodeMenuProps } from '../../AntimodeMenu';
 import { LinkPopup } from '../../linking/LinkPopup';
 import { gptAPICall, GPTCallType } from '../../../apis/gpt/GPT';
 // import { GPTPopup, GPTPopupMode } from './../../GPTPopup/GPTPopup';
@@ -15,6 +15,7 @@ import './MapAnchorMenu.scss';
 import { ColorPicker, Group, IconButton, Popup, Size, Toggle, ToggleType, Type } from 'browndash-components';
 import { StrCast } from '../../../../fields/Types';
 import { DocumentType } from '../../../documents/DocumentTypes';
+import { SettingsManager } from '../../../util/SettingsManager';
 
 @observer
 export class MapAnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
@@ -24,9 +25,6 @@ export class MapAnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
     private _disposer2: IReactionDisposer | undefined;
     private _commentCont = React.createRef<HTMLButtonElement>();
 
-
-
-
     public onMakeAnchor: () => Opt<Doc> = () => undefined; // Method to get anchor from text search
 
     public Center: () => void = unimplementedFunction;
@@ -90,41 +88,39 @@ export class MapAnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
     //     );
     // };
 
-
     static top = React.createRef<HTMLDivElement>();
     // public get Top(){
     //     return this.top
     // }
 
-
     render() {
-        const buttons =(
-                <>
-                    {(
-                        <IconButton
-                            tooltip="Delete Pin" //
-                            onPointerDown={this.Delete}
-                            icon={<FontAwesomeIcon icon="trash-alt" />}
-                            color={StrCast(Doc.UserDoc().userColor)}
-                        />
-                    )}
-                    {(
-                        <IconButton
-                            tooltip="Link Note to Pin" //
-                            onPointerDown={this.LinkNote}
-                            icon={<FontAwesomeIcon icon="sticky-note" />}
-                            color={StrCast(Doc.UserDoc().userColor)}
-                        />
-                    )}
-                    {(
-                        <IconButton
-                            tooltip="Center on pin" //
-                            onPointerDown={this.Center}
-                            icon={<FontAwesomeIcon icon="compress-arrows-alt" />}
-                            color={StrCast(Doc.UserDoc().userColor)}
-                        />
-                    )}
-                    {/* {this.IsTargetToggler !== returnFalse && (
+        const buttons = (
+            <>
+                {
+                    <IconButton
+                        tooltip="Delete Pin" //
+                        onPointerDown={this.Delete}
+                        icon={<FontAwesomeIcon icon="trash-alt" />}
+                        color={SettingsManager.userColor}
+                    />
+                }
+                {
+                    <IconButton
+                        tooltip="Link Note to Pin" //
+                        onPointerDown={this.LinkNote}
+                        icon={<FontAwesomeIcon icon="sticky-note" />}
+                        color={SettingsManager.userColor}
+                    />
+                }
+                {
+                    <IconButton
+                        tooltip="Center on pin" //
+                        onPointerDown={this.Center}
+                        icon={<FontAwesomeIcon icon="compress-arrows-alt" />}
+                        color={SettingsManager.userColor}
+                    />
+                }
+                {/* {this.IsTargetToggler !== returnFalse && (
                         <Toggle
                             tooltip={'Make target visibility toggle on click'}
                             type={Type.PRIM}
@@ -132,15 +128,16 @@ export class MapAnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
                             toggleStatus={this.IsTargetToggler()}
                             onClick={this.MakeTargetToggle}
                             icon={<FontAwesomeIcon icon="thumbtack" />}
-                            color={StrCast(Doc.UserDoc().userColor)}
+                            color={SettingsManager.userColor}
                         />
                     )} */}
-                </>
-            );
+            </>
+        );
 
-        return this.getElement(<div ref={MapAnchorMenu.top} style={{width:"100%", display:"flex"}}>
-        {buttons}
-        </div>
+        return this.getElement(
+            <div ref={MapAnchorMenu.top} style={{ width: '100%', display: 'flex' }}>
+                {buttons}
+            </div>
         );
     }
 }
diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx
index 01810fa00..81ca3ff36 100644
--- a/src/client/views/nodes/MapBox/MapBox.tsx
+++ b/src/client/views/nodes/MapBox/MapBox.tsx
@@ -760,8 +760,9 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                             ? null
                             : this.allAnnotations
                                   .filter(anno => !anno.layout_unrendered)
-                                  .map(pushpin => (
+                                  .map((pushpin, i) => (
                                       <DocumentView
+                                          key={i}
                                           {...this.props}
                                           renderDepth={this.props.renderDepth + 1}
                                           Document={pushpin}
-- 
cgit v1.2.3-70-g09d2


From 74e72adabd59fc58107fd73590f1e7e9cbaf4bde Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 11 Sep 2023 23:19:59 -0400
Subject: clean up some runtime warnings about missing keys/values

---
 package-lock.json                         | 6 +++---
 package.json                              | 2 +-
 src/client/views/MainViewModal.tsx        | 3 ++-
 src/client/views/collections/TreeView.tsx | 6 +++---
 src/client/views/nodes/KeyValuePair.tsx   | 2 +-
 src/client/views/search/SearchBox.tsx     | 4 ++--
 6 files changed, 12 insertions(+), 11 deletions(-)

(limited to 'src/client/views/collections/TreeView.tsx')

diff --git a/package-lock.json b/package-lock.json
index d15959b7d..e0e54769a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -6687,9 +6687,9 @@
             }
         },
         "browndash-components": {
-            "version": "0.1.35",
-            "resolved": "https://registry.npmjs.org/browndash-components/-/browndash-components-0.1.35.tgz",
-            "integrity": "sha512-xA4ACEppnDe5ThnUZPn9vo4W/KeZJZT5EFWh2tM0IsH/ZfcOhJopGfV6ZoIHHpvS5f/zi6l7YJuWaxd+aK5arg==",
+            "version": "0.1.36",
+            "resolved": "https://registry.npmjs.org/browndash-components/-/browndash-components-0.1.36.tgz",
+            "integrity": "sha512-++Xxn67r9ETz7pQr9dE09dMgPJ6rltEzwYWifpI98AQct4RmEBfiPp5eLG94+143XllxZy++KBf9YJ8AYpTEkQ==",
             "requires": {
                 "@emotion/react": "^11.11.1",
                 "@emotion/styled": "^11.11.0",
diff --git a/package.json b/package.json
index 92ebf0b0f..67fdedeb2 100644
--- a/package.json
+++ b/package.json
@@ -178,7 +178,7 @@
         "body-parser": "^1.19.2",
         "bootstrap": "^4.6.1",
         "brotli": "^1.3.3",
-        "browndash-components": "^0.1.35",
+        "browndash-components": "^0.1.36",
         "browser-assert": "^1.2.1",
         "bson": "^4.6.1",
         "canvas": "^2.9.3",
diff --git a/src/client/views/MainViewModal.tsx b/src/client/views/MainViewModal.tsx
index d0a79eb70..67b722e7a 100644
--- a/src/client/views/MainViewModal.tsx
+++ b/src/client/views/MainViewModal.tsx
@@ -3,6 +3,7 @@ import { observer } from 'mobx-react';
 import * as React from 'react';
 import { Doc } from '../../fields/Doc';
 import { StrCast } from '../../fields/Types';
+import { SettingsManager } from '../util/SettingsManager';
 import './MainViewModal.scss';
 
 export interface MainViewOverlayProps {
@@ -44,7 +45,7 @@ export class MainViewModal extends React.Component<MainViewOverlayProps> {
                     className="overlay"
                     onClick={this.props?.closeOnExternalClick}
                     style={{
-                        backgroundColor: isDark(StrCast(Doc.UserDoc().userColor)) ? '#DFDFDF30' : '#32323230',
+                        backgroundColor: isDark(SettingsManager.userColor) ? '#DFDFDF30' : '#32323230',
                         ...(p.overlayStyle || {}),
                     }}
                 />
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 71e9f4dfa..832e102bc 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -1015,8 +1015,8 @@ export class TreeView extends React.Component<TreeViewProps> {
                     ref={this._tref}
                     title="click to edit title. Double Click or Drag to Open"
                     style={{
-                        backgroundColor: Doc.IsSystem(this.props.document) || this.props.document.isFolder ? StrCast(Doc.UserDoc().userVariantColor) : undefined,
-                        color: Doc.IsSystem(this.props.document) || this.props.document.isFolder ? lightOrDark(StrCast(Doc.UserDoc().userVariantColor)) : undefined,
+                        backgroundColor: Doc.IsSystem(this.props.document) || this.props.document.isFolder ? SettingsManager.userVariantColor : undefined,
+                        color: Doc.IsSystem(this.props.document) || this.props.document.isFolder ? lightOrDark(SettingsManager.userVariantColor) : undefined,
                         fontWeight: Doc.IsSearchMatch(this.doc) !== undefined ? 'bold' : undefined,
                         textDecoration: Doc.GetT(this.doc, 'title', 'string', true) ? 'underline' : undefined,
                         outline: this.doc === Doc.ActiveDashboard ? 'dashed 1px #06123232' : undefined,
@@ -1045,7 +1045,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                     <div
                         className="treeView-background"
                         style={{
-                            background: StrCast(Doc.UserDoc().userColor),
+                            background: SettingsManager.userColor,
                         }}
                     />
                     {contents}
diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx
index b0d041bdd..f22cb195f 100644
--- a/src/client/views/nodes/KeyValuePair.tsx
+++ b/src/client/views/nodes/KeyValuePair.tsx
@@ -111,7 +111,7 @@ export class KeyValuePair extends React.Component<KeyValuePairProps> {
                             X
                         </button>
                         <input className="keyValuePair-td-key-check" type="checkbox" style={hover} onChange={this.handleCheck} ref={this.checkbox} />
-                        <Tooltip title={Object.entries(new DocumentOptions()).find((pair: [string, FInfo]) => pair[0].replace(/^_/, '') === props.fieldKey)?.[1].description}>
+                        <Tooltip title={Object.entries(new DocumentOptions()).find((pair: [string, FInfo]) => pair[0].replace(/^_/, '') === props.fieldKey)?.[1].description ?? ''}>
                             <div className="keyValuePair-keyField" style={{ marginLeft: 20 * (props.fieldKey.match(/_/g)?.length || 0), color: keyStyle }}>
                                 {'('.repeat(parenCount)}
                                 {props.fieldKey}
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 6b6b0f2ff..aa46e57dc 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -453,7 +453,7 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
                 </div>
                 {resultsJSX.length > 0 && (
                     <div className="searchBox-results-container">
-                        <div className="section-header" style={{ background: StrCast(Doc.UserDoc().userVariantColor, Colors.MEDIUM_BLUE) }}>
+                        <div className="section-header" style={{ background: SettingsManager.userVariantColor }}>
                             <div className="section-title">Results</div>
                             <div className="section-subtitle">{`${validResults}` + ' result' + (validResults === 1 ? '' : 's')}</div>
                         </div>
@@ -462,7 +462,7 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
                 )}
                 {recommendationsJSX.length > 0 && (
                     <div className="searchBox-recommendations-container">
-                        <div className="section-header" style={{ background: StrCast(Doc.UserDoc().userVariantColor, Colors.MEDIUM_BLUE) }}>
+                        <div className="section-header" style={{ background: SettingsManager.userVariantColor }}>
                             <div className="section-title">Recommendations</div>
                             <div className="section-subtitle">{`${validResults}` + ' result' + (validResults === 1 ? '' : 's')}</div>
                         </div>
-- 
cgit v1.2.3-70-g09d2


From c9ce658d193d5e8ec4161c31bc60c499ada1b8b7 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 19 Sep 2023 16:28:40 -0400
Subject: fixed tree view hierarchy opening icons

---
 src/client/views/collections/TreeView.scss           | 4 +++-
 src/client/views/collections/TreeView.tsx            | 2 +-
 src/client/views/nodes/formattedText/DashDocView.tsx | 1 -
 3 files changed, 4 insertions(+), 3 deletions(-)

(limited to 'src/client/views/collections/TreeView.tsx')

diff --git a/src/client/views/collections/TreeView.scss b/src/client/views/collections/TreeView.scss
index 0cc11bf1c..cbcc7c710 100644
--- a/src/client/views/collections/TreeView.scss
+++ b/src/client/views/collections/TreeView.scss
@@ -21,7 +21,7 @@
     }
 
     .treeView-bulletIcons {
-        width: 100%;
+        margin: auto;
         height: 100%;
         // changes start here.
 
@@ -64,6 +64,8 @@
         position: relative;
         width: fit-content;
         min-height: 20px;
+        min-width: 15px;
+        margin-right: 3px;
         color: $medium-gray;
         border: #80808030 1px solid;
         border-radius: 5px;
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 832e102bc..cd526c77e 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -761,7 +761,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                         <IconButton color={color} icon={<FontAwesomeIcon icon={[this.childDocs?.length && !this.treeViewOpen ? 'fas' : 'far', 'circle']} />} size={Size.XSMALL} />
                     )
                 ) : (
-                    <div className="treeView-bulletIcons" style={{ color: Doc.IsSystem(DocCast(this.doc.proto)) ? 'red' : undefined }}>
+                    <div className="treeView-bulletIcons">
                         <div className={`treeView-${this.onCheckedClick ? 'checkIcon' : 'expandIcon'}`}>
                             <FontAwesomeIcon
                                 size="sm"
diff --git a/src/client/views/nodes/formattedText/DashDocView.tsx b/src/client/views/nodes/formattedText/DashDocView.tsx
index 5349e6966..c5167461b 100644
--- a/src/client/views/nodes/formattedText/DashDocView.tsx
+++ b/src/client/views/nodes/formattedText/DashDocView.tsx
@@ -8,7 +8,6 @@ import { NumCast, StrCast } from '../../../../fields/Types';
 import { emptyFunction, returnFalse, Utils } from '../../../../Utils';
 import { DocServer } from '../../../DocServer';
 import { Docs, DocUtils } from '../../../documents/Documents';
-import { ColorScheme } from '../../../util/SettingsManager';
 import { Transform } from '../../../util/Transform';
 import { DocFocusOptions, DocumentView } from '../DocumentView';
 import { FormattedTextBox } from './FormattedTextBox';
-- 
cgit v1.2.3-70-g09d2


From 34f3bab0f4d55b2f55f38e451bfd024994ecff42 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 20 Sep 2023 13:20:53 -0400
Subject: added carousel3D to novice and fixed it's button positions and its
 focus so that it works with trails. added dragging documents within single
 collection for rearranging order of docs in a tab collection.  fixed freeform
 views set to fitWidth to show decorations properly. turned off scaling of
 tree views.  updated lightbox buttons.  fixed tooltips on properties toggles.

---
 src/client/util/CurrentUserUtils.ts                |   4 +-
 src/client/util/DragManager.ts                     |   2 +-
 src/client/views/LightboxView.scss                 |  11 +--
 src/client/views/LightboxView.tsx                  | 106 +++++++++++++--------
 src/client/views/PropertiesButtons.tsx             |  12 ++-
 .../views/collections/CollectionCarousel3DView.tsx |  17 +++-
 src/client/views/collections/CollectionSubView.tsx |   5 +-
 .../views/collections/CollectionTreeView.tsx       |   4 +-
 src/client/views/collections/TreeView.tsx          |   6 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  |   9 +-
 src/client/views/nodes/FontIconBox/FontIconBox.tsx |   2 +-
 11 files changed, 109 insertions(+), 69 deletions(-)

(limited to 'src/client/views/collections/TreeView.tsx')

diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 259c028cc..2ea5972ee 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -492,8 +492,8 @@ export class CurrentUserUtils {
         const childContextMenuIcons = ["tv", "camera", "users", "times", "trash"]; // entries must be kept in synch with childContextMenuScripts, childContextMenuLabels, and childContextMenuFilters
         const reqdOpts:DocumentOptions = {
             title: "My Dashboards", childHideLinkButton: true, treeView_FreezeChildren: "remove|add", treeView_HideTitle: true, layout_boxShadow: "0 0", childDontRegisterViews: true,
-            dropAction: "same", treeView_Type: TreeViewType.fileSystem, isFolder: true, isSystem: true,  treeView_TruncateTitleWidth: 350, ignoreClick: true, 
-            layout_headerButton: newDashboardButton, childDragAction: "none",
+            dropAction: "inSame", treeView_Type: TreeViewType.fileSystem, isFolder: true, isSystem: true,  treeView_TruncateTitleWidth: 350, ignoreClick: true, 
+            layout_headerButton: newDashboardButton, childDragAction: "inSame",
             _layout_showTitle: "title", _height: 400, _gridGap: 5, _forceActive: true, _lockedPosition: true,
             contextMenuLabels:new List<string>(contextMenuLabels),
             contextMenuIcons:new List<string>(contextMenuIcons),
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index ed22e70bd..f86f9a3e5 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -14,7 +14,7 @@ import { SelectionManager } from './SelectionManager';
 import { SnappingManager } from './SnappingManager';
 import { UndoManager } from './UndoManager';
 
-export type dropActionType = 'embed' | 'copy' | 'move' | 'add' | 'same' | 'proto' | 'none' | undefined; // undefined = move, "same" = move but don't call dropPropertiesToRemove
+export type dropActionType = 'embed' | 'copy' | 'move' | 'add' | 'same' | 'inSame' | 'proto' | 'none' | undefined; // undefined = move, "same" = move but don't call dropPropertiesToRemove
 
 /**
  * Initialize drag
diff --git a/src/client/views/LightboxView.scss b/src/client/views/LightboxView.scss
index f86a1d211..9a9b8a437 100644
--- a/src/client/views/LightboxView.scss
+++ b/src/client/views/LightboxView.scss
@@ -5,7 +5,6 @@
     top: 10;
     background: transparent;
     border-radius: 8;
-    color: white;
     opacity: 0.7;
     width: 25;
     flex-direction: column;
@@ -17,11 +16,10 @@
 .lightboxView-tabBtn {
     margin: auto;
     position: absolute;
-    right: 38;
+    right: 45;
     top: 10;
     background: transparent;
     border-radius: 8;
-    color: white;
     opacity: 0.7;
     width: 25;
     flex-direction: column;
@@ -33,11 +31,10 @@
 .lightboxView-penBtn {
     margin: auto;
     position: absolute;
-    right: 70;
+    right: 80;
     top: 10;
     background: transparent;
     border-radius: 8;
-    color: white;
     opacity: 0.7;
     width: 25;
     flex-direction: column;
@@ -49,11 +46,10 @@
 .lightboxView-exploreBtn {
     margin: auto;
     position: absolute;
-    right: 100;
+    right: 115;
     top: 10;
     background: transparent;
     border-radius: 8;
-    color: white;
     opacity: 0.7;
     width: 25;
     flex-direction: column;
@@ -68,7 +64,6 @@
     left: 0;
     width: 100%;
     height: 100%;
-    background: #000000bb;
     z-index: 1000;
     .lightboxView-contents {
         position: absolute;
diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx
index 8f081b321..93eaec959 100644
--- a/src/client/views/LightboxView.tsx
+++ b/src/client/views/LightboxView.tsx
@@ -1,15 +1,17 @@
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { Toggle, ToggleType, Type } from 'browndash-components';
 import { action, computed, observable } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
 import { Doc, DocListCast, Opt } from '../../fields/Doc';
 import { InkTool } from '../../fields/InkField';
-import { Cast, NumCast, StrCast } from '../../fields/Types';
+import { BoolCast, Cast, NumCast, StrCast } from '../../fields/Types';
 import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnTrue } from '../../Utils';
 import { DocUtils } from '../documents/Documents';
 import { DocumentManager } from '../util/DocumentManager';
 import { LinkManager } from '../util/LinkManager';
 import { SelectionManager } from '../util/SelectionManager';
+import { SettingsManager } from '../util/SettingsManager';
 import { Transform } from '../util/Transform';
 import { CollectionDockingView } from './collections/CollectionDockingView';
 import { CollectionStackedTimeline } from './collections/CollectionStackedTimeline';
@@ -118,7 +120,7 @@ export class LightboxView extends React.Component<LightboxViewProps> {
                     width: bottom !== undefined ? undefined : Math.min(this.props.PanelWidth / 4, this.props.maxBorder[0]),
                     bottom,
                 }}>
-                <div className="lightboxView-navBtn" title={color} style={{ top, color: color ? 'red' : 'white', background: color ? 'white' : undefined }} onClick={click}>
+                <div className="lightboxView-navBtn" title={color} style={{ top, color: SettingsManager.userColor, background: undefined }} onClick={click}>
                     <div style={{ height: 10 }}>{color}</div>
                     <FontAwesomeIcon icon={icon as any} size="3x" />
                 </div>
@@ -229,6 +231,7 @@ export class LightboxView extends React.Component<LightboxViewProps> {
                     downx = e.clientX;
                     downy = e.clientY;
                 }}
+                style={{ background: SettingsManager.userBackgroundColor }}
                 onClick={e => {
                     if (Math.abs(downx - e.clientX) < 4 && Math.abs(downy - e.clientY) < 4) {
                         LightboxView.SetLightboxDoc(undefined);
@@ -242,6 +245,8 @@ export class LightboxView extends React.Component<LightboxViewProps> {
                         width: this.lightboxWidth(),
                         height: this.lightboxHeight(),
                         clipPath: `path('${Doc.UserDoc().renderStyle === 'comic' ? wavyBorderPath(this.lightboxWidth(), this.lightboxHeight()) : undefined}')`,
+                        background: SettingsManager.userBackgroundColor,
+                        color: SettingsManager.userColor,
                     }}>
                     {/* <CollectionMenu /> TODO:glr This is where it would go*/}
 
@@ -299,47 +304,68 @@ export class LightboxView extends React.Component<LightboxViewProps> {
                     this.future()?.length.toString()
                 )}
                 <LightboxTourBtn navBtn={this.navBtn} future={this.future} stepInto={this.stepInto} />
-                <div
-                    className="lightboxView-navBtn"
-                    title="toggle fit width"
-                    onClick={e => {
-                        e.stopPropagation();
-                        LightboxView.LightboxDoc!._layout_fitWidth = !LightboxView.LightboxDoc!._layout_fitWidth;
-                    }}>
-                    <FontAwesomeIcon icon={LightboxView.LightboxDoc?._layout_fitWidth ? 'arrows-alt-h' : 'arrows-alt-v'} size="2x" />
+                <div className="lightboxView-navBtn">
+                    <Toggle
+                        tooltip="toggle reading view"
+                        color={SettingsManager.userColor}
+                        background={BoolCast(LightboxView.LightboxDoc!._layout_fitWidth) ? SettingsManager.userVariantColor : SettingsManager.userBackgroundColor}
+                        toggleType={ToggleType.BUTTON}
+                        type={Type.TERT}
+                        toggleStatus={BoolCast(LightboxView.LightboxDoc!._layout_fitWidth)}
+                        onClick={e => {
+                            e.stopPropagation();
+                            LightboxView.LightboxDoc!._layout_fitWidth = !LightboxView.LightboxDoc!._layout_fitWidth;
+                        }}
+                        icon={<FontAwesomeIcon icon={LightboxView.LightboxDoc?._layout_fitWidth ? 'book-open' : 'book'} size="sm" />}
+                    />
                 </div>
-                <div
-                    className="lightboxView-tabBtn"
-                    title="open in tab"
-                    onClick={e => {
-                        const lightdoc = LightboxView._docTarget || LightboxView._doc!;
-                        e.stopPropagation();
-                        Doc.RemoveDocFromList(Doc.MyRecentlyClosed, 'data', lightdoc);
-                        CollectionDockingView.AddSplit(lightdoc, OpenWhereMod.none);
-                        SelectionManager.DeselectAll();
-                        LightboxView.SetLightboxDoc(undefined);
-                    }}>
-                    <FontAwesomeIcon icon={'file-download'} size="2x" />
+                <div className="lightboxView-tabBtn">
+                    <Toggle
+                        tooltip="open document in a tab"
+                        color={SettingsManager.userColor}
+                        background={SettingsManager.userBackgroundColor}
+                        toggleType={ToggleType.BUTTON}
+                        type={Type.TERT}
+                        icon={<FontAwesomeIcon icon="file-download" size="sm" />}
+                        onClick={e => {
+                            const lightdoc = LightboxView._docTarget || LightboxView._doc!;
+                            e.stopPropagation();
+                            Doc.RemoveDocFromList(Doc.MyRecentlyClosed, 'data', lightdoc);
+                            CollectionDockingView.AddSplit(lightdoc, OpenWhereMod.none);
+                            SelectionManager.DeselectAll();
+                            LightboxView.SetLightboxDoc(undefined);
+                        }}
+                    />
                 </div>
-                <div
-                    className="lightboxView-penBtn"
-                    title="toggle pen annotation"
-                    style={{ background: Doc.ActiveTool === InkTool.Pen ? 'white' : undefined }}
-                    onClick={e => {
-                        e.stopPropagation();
-                        Doc.ActiveTool = Doc.ActiveTool === InkTool.Pen ? InkTool.None : InkTool.Pen;
-                    }}>
-                    <FontAwesomeIcon color={Doc.ActiveTool === InkTool.Pen ? 'black' : 'white'} icon={'pen'} size="2x" />
+                <div className="lightboxView-penBtn">
+                    <Toggle
+                        tooltip="toggle pen annotation"
+                        color={SettingsManager.userColor}
+                        background={Doc.ActiveTool === InkTool.Pen ? SettingsManager.userVariantColor : SettingsManager.userBackgroundColor}
+                        toggleType={ToggleType.BUTTON}
+                        toggleStatus={Doc.ActiveTool === InkTool.Pen}
+                        type={Type.TERT}
+                        icon={<FontAwesomeIcon icon="pen" size="sm" />}
+                        onClick={e => {
+                            e.stopPropagation();
+                            Doc.ActiveTool = Doc.ActiveTool === InkTool.Pen ? InkTool.None : InkTool.Pen;
+                        }}
+                    />
                 </div>
-                <div
-                    className="lightboxView-exploreBtn"
-                    title="toggle explore mode to navigate among documents only"
-                    style={{ background: DocumentView.ExploreMode ? 'white' : undefined }}
-                    onClick={action(e => {
-                        e.stopPropagation();
-                        DocumentView.ExploreMode = !DocumentView.ExploreMode;
-                    })}>
-                    <FontAwesomeIcon color={DocumentView.ExploreMode ? 'black' : 'white'} icon={'globe-americas'} size="2x" />
+                <div className="lightboxView-exploreBtn">
+                    <Toggle
+                        tooltip="toggle explore mode to navigate among documents only"
+                        color={SettingsManager.userColor}
+                        background={DocumentView.ExploreMode ? SettingsManager.userVariantColor : SettingsManager.userBackgroundColor}
+                        toggleType={ToggleType.BUTTON}
+                        type={Type.TERT}
+                        toggleStatus={DocumentView.ExploreMode}
+                        icon={<FontAwesomeIcon icon="globe-americas" size="sm" />}
+                        onClick={action(e => {
+                            e.stopPropagation();
+                            DocumentView.ExploreMode = !DocumentView.ExploreMode;
+                        })}
+                    />
                 </div>
             </div>
         );
diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx
index 40d42a4de..d1561fd67 100644
--- a/src/client/views/PropertiesButtons.tsx
+++ b/src/client/views/PropertiesButtons.tsx
@@ -57,6 +57,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
         return !targetDoc ? null : (
             <Toggle
                 toggleStatus={BoolCast(targetDoc[property])}
+                tooltip={tooltip(BoolCast(targetDoc[property]))}
                 text={label(targetDoc?.[property])}
                 color={SettingsManager.userColor}
                 icon={icon(targetDoc?.[property] as any)}
@@ -165,9 +166,9 @@ export class PropertiesButtons extends React.Component<{}, {}> {
     @computed get forceActiveButton() {
         //select text
         return this.propertyToggleBtn(
-            on => (on ? 'INACTIVE INTERACTION' : 'ACTIVE INTERACTION'),
+            on => (on ? 'SELECT TO INTERACT' : 'ALWAYS INTERACTIVE'),
             '_forceActive',
-            on => `${on ? 'Select to activate' : 'Contents always active'} `,
+            on => `${on ? 'Document must be selected to interact with its contents' : 'Contents always active (respond to click/drag events)'} `,
             on => <MdTouchApp /> // 'eye'
         );
     }
@@ -210,9 +211,12 @@ export class PropertiesButtons extends React.Component<{}, {}> {
 
     @computed get layout_fitWidthButton() {
         return this.propertyToggleBtn(
-            on => (on ? 'RESTRICT WIDTH' : 'FIT WIDTH'), //'Fit\xA0Width',
+            on => (on ? 'SCALED VIEW' : 'READING VIEW'), //'Fit\xA0Width',
             '_layout_fitWidth',
-            on => `${on ? "Don't" : 'Do'} fit content to width of container`,
+            on =>
+                on
+                    ? "Scale document so it's width and height fit container (no effect when document is viewed on freeform canvas)"
+                    : "Scale document so it's width fits container and its height expands/contracts to fit available space  (no effect when document is viewed on freeform canvas)",
             on => (on ? <AiOutlineColumnWidth /> : <RxWidth />) // 'arrows-alt-h'
         );
     }
diff --git a/src/client/views/collections/CollectionCarousel3DView.tsx b/src/client/views/collections/CollectionCarousel3DView.tsx
index d94e552b4..cd59a91a1 100644
--- a/src/client/views/collections/CollectionCarousel3DView.tsx
+++ b/src/client/views/collections/CollectionCarousel3DView.tsx
@@ -2,14 +2,15 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { computed } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
-import { Doc } from '../../../fields/Doc';
+import { Doc, DocListCast } from '../../../fields/Doc';
 import { Id } from '../../../fields/FieldSymbols';
-import { NumCast, ScriptCast, StrCast } from '../../../fields/Types';
+import { DocCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
 import { returnFalse, returnZero, Utils } from '../../../Utils';
+import { DocumentType } from '../../documents/DocumentTypes';
 import { DragManager } from '../../util/DragManager';
 import { SelectionManager } from '../../util/SelectionManager';
 import { CAROUSEL3D_CENTER_SCALE, CAROUSEL3D_SIDE_SCALE, CAROUSEL3D_TOP } from '../global/globalCssVariables.scss';
-import { DocumentView } from '../nodes/DocumentView';
+import { DocFocusOptions, DocumentView } from '../nodes/DocumentView';
 import { StyleProp } from '../StyleProvider';
 import './CollectionCarousel3DView.scss';
 import { CollectionSubView } from './CollectionSubView';
@@ -46,6 +47,15 @@ export class CollectionCarousel3DView extends CollectionSubView() {
             .translate(-this.panelWidth() + ((this.centerScale - 1) * this.panelWidth()) / 2, -((Number(CAROUSEL3D_TOP) / 100) * this.props.PanelHeight()) + ((this.centerScale - 1) * this.panelHeight()) / 2)
             .scale(1 / this.centerScale);
 
+    focus = (anchor: Doc, options: DocFocusOptions) => {
+        const docs = DocListCast(this.Document[this.fieldKey ?? Doc.LayoutFieldKey(this.Document)]);
+        if (anchor.type !== DocumentType.CONFIG && !docs.includes(anchor)) return;
+        options.didMove = true;
+        const target = DocCast(anchor.annotationOn) ?? anchor;
+        const index = docs.indexOf(target);
+        index !== -1 && (this.layoutDoc._carousel_index = index);
+        return undefined;
+    };
     @computed get content() {
         const currentIndex = NumCast(this.layoutDoc._carousel_index);
         const displayDoc = (childPair: { layout: Doc; data: Doc }) => {
@@ -61,6 +71,7 @@ export class CollectionCarousel3DView extends CollectionSubView() {
                     LayoutTemplateString={this.props.childLayoutString}
                     Document={childPair.layout}
                     DataDoc={childPair.data}
+                    focus={this.focus}
                     ScreenToLocalTransform={this.childScreenToLocal}
                     isContentActive={this.isChildContentActive}
                     isDocumentActive={this.props.childDocumentsActive?.() || this.Document._childDocumentsActive ? this.props.isDocumentActive : this.isContentActive}
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 54a60271a..26272d2ee 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -210,11 +210,12 @@ export function CollectionSubView<X>(moreProps?: X) {
                 const targetDocments = DocListCast(this.dataDoc[this.props.fieldKey]);
                 const someMoved = !dropAction && docDragData.draggedDocuments.some(drag => targetDocments.includes(drag));
                 if (someMoved) docDragData.droppedDocuments = docDragData.droppedDocuments.map((drop, i) => (targetDocments.includes(docDragData.draggedDocuments[i]) ? docDragData.draggedDocuments[i] : drop));
-                if ((!dropAction || dropAction === 'same' || dropAction === 'move' || someMoved) && docDragData.moveDocument) {
+                if ((!dropAction || dropAction === 'inSame' || dropAction === 'same' || dropAction === 'move' || someMoved) && docDragData.moveDocument) {
                     const movedDocs = docDragData.droppedDocuments.filter((d, i) => docDragData.draggedDocuments[i] === d);
                     const addedDocs = docDragData.droppedDocuments.filter((d, i) => docDragData.draggedDocuments[i] !== d);
                     if (movedDocs.length) {
-                        const canAdd = de.embedKey || dropAction || Doc.AreProtosEqual(Cast(movedDocs[0].annotationOn, Doc, null), this.rootDoc);
+                        const canAdd =
+                            (de.embedKey || dropAction || Doc.AreProtosEqual(Cast(movedDocs[0].annotationOn, Doc, null), this.rootDoc)) && (dropAction !== 'inSame' || docDragData.draggedDocuments.every(d => d.embedContainer === this.rootDoc));
                         const moved = docDragData.moveDocument(movedDocs, this.rootDoc, canAdd ? this.addDocument : returnFalse);
                         added = canAdd || moved ? moved : undefined;
                     } else {
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index eed04b3ee..9e5ac77d9 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -149,7 +149,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
             if (isAlreadyInTree() !== sameTree) {
                 console.log('WHAAAT');
             }
-            dragData.dropAction = dropAction && !isAlreadyInTree() ? dropAction : sameTree ? 'same' : dragData.dropAction;
+            dragData.dropAction = dropAction && !isAlreadyInTree() ? dropAction : sameTree && dragData.dropAction !== 'inSame' ? 'same' : dragData.dropAction;
             e.stopPropagation();
         }
     };
@@ -438,7 +438,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
     render() {
         TraceMobx();
 
-        const scale = (this.props.NativeDimScaling?.() || 1) * NumCast(this.layoutDoc._freeform_scale, 1) || 1;
+        const scale = this.props.NativeDimScaling?.() || 1;
         return (
             <div style={{ transform: `scale(${scale})`, transformOrigin: 'top left', width: `${100 / scale}%`, height: `${100 / scale}%` }}>
                 {!(this.doc instanceof Doc) || !this.treeChildren ? null : this.doc.treeView_HasOverlay ? (
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index cd526c77e..f89aa065b 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -433,9 +433,9 @@ export class TreeView extends React.Component<TreeViewProps> {
             return (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && innerAdd(doc), true as boolean);
         };
         const addDoc = inside ? localAdd : parentAddDoc;
-        const move = (!dropAction || dropAction === 'proto' || dropAction === 'move' || dropAction === 'same') && moveDocument;
+        const move = (!dropAction || dropAction === 'proto' || dropAction === 'move' || dropAction === 'same' || dropAction === 'inSame') && moveDocument;
         const canAdd = (!this.props.treeView.outlineMode && !StrCast((inside ? this.props.document : this.props.treeViewParent)?.treeView_FreezeChildren).includes('add')) || forceAdd;
-        if (canAdd) {
+        if (canAdd && (dropAction !== 'inSame' || droppedDocuments.every(d => d.embedContainer === this.props.parentTreeView?.doc))) {
             this.props.parentTreeView instanceof TreeView && (this.props.parentTreeView.dropping = true);
             const res = droppedDocuments.reduce((added, d) => (move ? move(d, undefined, addDoc) || (dropAction === 'proto' ? addDoc(d) : false) : addDoc(d)) || added, false);
             this.props.parentTreeView instanceof TreeView && (this.props.parentTreeView.dropping = false);
@@ -598,7 +598,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                 }
                 const dataIsComputed = ComputedField.WithoutComputed(() => FieldValue(this.dataDoc[key])) instanceof ComputedField;
                 const added = (!dataIsComputed || (this.dropping && this.moving)) && Doc.AddDocToList(this.dataDoc, key, doc, addBefore, before, false, true);
-                !dataIsComputed && added && Doc.SetContainer(doc, DocCast(this.doc.embedContainer));
+                !dataIsComputed && added && Doc.SetContainer(doc, this.doc);
 
                 return added;
             };
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 8a812c671..9df96fabc 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -33,7 +33,6 @@ import { undoBatch, UndoManager } from '../../../util/UndoManager';
 import { COLLECTION_BORDER_WIDTH } from '../../../views/global/globalCssVariables.scss';
 import { Timeline } from '../../animationtimeline/Timeline';
 import { ContextMenu } from '../../ContextMenu';
-import { DocumentDecorations } from '../../DocumentDecorations';
 import { GestureOverlay } from '../../GestureOverlay';
 import { ActiveArrowEnd, ActiveArrowStart, ActiveDash, ActiveFillColor, ActiveInkBezierApprox, ActiveInkColor, ActiveInkWidth, ActiveIsInkMask, InkingStroke, SetActiveInkColor, SetActiveInkWidth } from '../../InkingStroke';
 import { LightboxView } from '../../LightboxView';
@@ -187,7 +186,10 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         return this.props.ScreenToLocalTransform().translate(-this.borderWidth, -this.borderWidth);
     }
     @computed get cachedGetTransform(): Transform {
-        return this.getContainerTransform().translate(-this.cachedCenteringShiftX, -this.cachedCenteringShiftY).transform(this.cachedGetLocalTransform);
+        return this.getContainerTransform()
+            .scale(this.props.isAnnotationOverlay ? 1 : 1 / this.nativeDim())
+            .translate(-this.cachedCenteringShiftX, -this.cachedCenteringShiftY)
+            .transform(this.cachedGetLocalTransform);
     }
 
     public static gotoKeyframe(timer: NodeJS.Timeout | undefined, docs: Doc[], duration: number) {
@@ -862,7 +864,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 // create a new curve by appending all curves of the current segment together in order to render a single new stroke.
                 if (!e.shiftKey) {
                     this._eraserLock++;
-                    this.segmentInkStroke(intersect.inkView, intersect.t).forEach(segment =>
+                    const segments = this.segmentInkStroke(intersect.inkView, intersect.t);
+                    segments.forEach(segment =>
                         this.forceStrokeGesture(
                             e,
                             GestureUtils.Gestures.Stroke,
diff --git a/src/client/views/nodes/FontIconBox/FontIconBox.tsx b/src/client/views/nodes/FontIconBox/FontIconBox.tsx
index 394108be4..14a3d16ef 100644
--- a/src/client/views/nodes/FontIconBox/FontIconBox.tsx
+++ b/src/client/views/nodes/FontIconBox/FontIconBox.tsx
@@ -226,7 +226,7 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
             } else {
                 return <Button text="None Selected" type={Type.TERT} color={SettingsManager.userColor} background={SettingsManager.userVariantColor} fillWidth inactive />;
             }
-            noviceList = [CollectionViewType.Freeform, CollectionViewType.Schema, CollectionViewType.Stacking, CollectionViewType.NoteTaking];
+            noviceList = [CollectionViewType.Freeform, CollectionViewType.Schema, CollectionViewType.Carousel3D, CollectionViewType.Stacking, CollectionViewType.NoteTaking];
         } else {
             text = script?.script.run({ this: this.layoutDoc, self: this.rootDoc, value: '', _readOnly_: true }).result;
             // text = StrCast((RichTextMenu.Instance?.TextView?.EditorView ? RichTextMenu.Instance : Doc.UserDoc()).fontFamily);
-- 
cgit v1.2.3-70-g09d2

