From 562e965cbc3d7629014ad3902e1177d5cbefd57c Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 6 Jun 2023 18:48:59 -0400
Subject: updated Symbol naming.  fixed various compile errors related to type
 checking.

---
 src/client/views/collections/CollectionTreeView.tsx | 19 ++++++++++---------
 1 file changed, 10 insertions(+), 9 deletions(-)

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

diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 095e34c39..969658238 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -1,6 +1,7 @@
 import { action, computed, IReactionDisposer, observable, reaction } from 'mobx';
 import { observer } from 'mobx-react';
-import { DataSym, Doc, DocListCast, HeightSym, Opt, StrListCast, WidthSym } from '../../../fields/Doc';
+import { Doc, DocListCast, Opt, StrListCast } from '../../../fields/Doc';
+import { DocData, Height, Width } from '../../../fields/DocSymbols';
 import { Id } from '../../../fields/FieldSymbols';
 import { InkTool } from '../../../fields/InkField';
 import { listSpec } from '../../../fields/Schema';
@@ -154,15 +155,15 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
     @action
     remove = (doc: Doc | Doc[]): boolean => {
         const docs = doc instanceof Doc ? [doc] : doc;
-        const targetDataDoc = this.doc[DataSym];
+        const targetDataDoc = this.doc[DocData];
         const value = DocListCast(targetDataDoc[this.props.fieldKey]);
         const result = value.filter(v => !docs.includes(v));
         if ((doc instanceof Doc ? [doc] : doc).some(doc => SelectionManager.Views().some(dv => Doc.AreProtosEqual(dv.rootDoc, doc)))) SelectionManager.DeselectAll();
-        if (result.length !== value.length) {
-            const ind = targetDataDoc[this.props.fieldKey].indexOf(doc);
-            const prev = ind && targetDataDoc[this.props.fieldKey][ind - 1];
+        if (result.length !== value.length && doc instanceof Doc) {
+            const ind = DocListCast(targetDataDoc[this.props.fieldKey]).indexOf(doc);
+            const prev = ind && DocListCast(targetDataDoc[this.props.fieldKey])[ind - 1];
             this.props.removeDocument?.(doc);
-            if (ind > 0) {
+            if (ind > 0 && prev) {
                 FormattedTextBox.SelectOnLoad = prev[Id];
                 DocumentManager.Instance.getDocumentView(prev, this.props.DocumentView?.())?.select(false);
             }
@@ -175,7 +176,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
     addDoc = (docs: Doc | Doc[], relativeTo: Opt<Doc>, before?: boolean): boolean => {
         const doAddDoc = (doc: Doc | Doc[]) =>
             (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => {
-                const res = flg && Doc.AddDocToList(this.doc[DataSym], this.props.fieldKey, doc, relativeTo, before);
+                const res = flg && Doc.AddDocToList(this.doc[DocData], this.props.fieldKey, doc, relativeTo, before);
                 res && (doc.embedContainer = this.props.Document);
                 return res;
             }, true);
@@ -368,8 +369,8 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
     marginX = () => NumCast(this.doc._xMargin);
     marginTop = () => NumCast(this.doc._yMargin);
     marginBot = () => NumCast(this.doc._yMargin);
-    documentTitleWidth = () => Math.min(this.layoutDoc?.[WidthSym](), this.panelWidth());
-    documentTitleHeight = () => (this.layoutDoc?.[HeightSym]() || 0) - NumCast(this.layoutDoc.layout_autoHeightMargins);
+    documentTitleWidth = () => Math.min(this.layoutDoc?.[Width](), this.panelWidth());
+    documentTitleHeight = () => (this.layoutDoc?.[Height]() || 0) - NumCast(this.layoutDoc.layout_autoHeightMargins);
     truncateTitleWidth = () => this.treeViewtruncateTitleWidth;
     onChildClick = () => this.props.onChildClick?.() || ScriptCast(this.doc.onChildClick);
     panelWidth = () => Math.max(0, this.props.PanelWidth() - 2 * this.marginX() * (this.props.NativeDimScaling?.() || 1));
-- 
cgit v1.2.3-70-g09d2


From bf16eca7a84adfdf1c5970e7e4793568ee70325d Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 13 Jun 2023 22:14:29 -0400
Subject: fixed updating cached docs when opening a backlinks collection. 
 added some FieldInfo types and added 'enumeration' field display in schema
 view.  fixed bug in schema view column sizing.   updated a bunch of standard
 field names to be more consistent.

---
 src/client/documents/Documents.ts                  | 471 +++++++++++----------
 src/client/util/CurrentUserUtils.ts                | 115 ++---
 src/client/util/DocumentManager.ts                 |   2 +-
 src/client/util/DragManager.ts                     |   2 +-
 src/client/util/LinkManager.ts                     |   2 +-
 src/client/util/TrackMovements.ts                  |   3 +-
 src/client/views/DashboardView.tsx                 |   9 +-
 src/client/views/DocComponent.tsx                  |   2 -
 src/client/views/DocumentButtonBar.tsx             |   2 +-
 src/client/views/DocumentDecorations.tsx           |  16 +-
 src/client/views/FilterPanel.tsx                   |  12 +-
 src/client/views/GestureOverlay.tsx                |   8 +-
 src/client/views/LightboxView.tsx                  |  12 +-
 src/client/views/MainView.tsx                      |  20 +-
 src/client/views/MarqueeAnnotator.tsx              |   2 +-
 src/client/views/OverlayView.tsx                   |   4 +-
 src/client/views/Palette.tsx                       |   4 +-
 src/client/views/PropertiesButtons.tsx             |   4 +-
 .../views/PropertiesDocBacklinksSelector.tsx       |   4 +-
 src/client/views/PropertiesView.tsx                |  44 +-
 src/client/views/SidebarAnnos.tsx                  |  12 +-
 src/client/views/StyleProvider.tsx                 |  23 +-
 src/client/views/TemplateMenu.tsx                  |   4 +-
 src/client/views/collections/CollectionMenu.tsx    |  10 +-
 .../views/collections/CollectionNoteTakingView.tsx | 104 ++---
 .../views/collections/CollectionPileView.tsx       |  21 +-
 .../collections/CollectionStackedTimeline.tsx      |  14 +-
 .../views/collections/CollectionStackingView.tsx   |  12 +-
 src/client/views/collections/CollectionSubView.tsx |  29 +-
 .../views/collections/CollectionTimeView.tsx       |  18 +-
 .../views/collections/CollectionTreeView.tsx       |  12 +-
 src/client/views/collections/TabDocView.tsx        |   8 +-
 src/client/views/collections/TreeView.tsx          |  24 +-
 .../CollectionFreeFormLinkView.tsx                 |  16 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  14 +-
 .../collections/collectionFreeForm/MarqueeView.tsx |   2 +-
 .../collectionLinear/CollectionLinearView.tsx      |  18 +-
 .../CollectionMulticolumnView.tsx                  |   4 +-
 .../CollectionMultirowView.tsx                     |   4 +-
 .../collectionSchema/CollectionSchemaView.scss     |   2 +-
 .../collectionSchema/CollectionSchemaView.tsx      |  56 +--
 .../collectionSchema/SchemaColumnHeader.tsx        |   3 +-
 .../collections/collectionSchema/SchemaRowBox.tsx  |  10 +-
 .../collectionSchema/SchemaTableCell.tsx           |  55 ++-
 src/client/views/linking/LinkMenuGroup.tsx         |   2 +-
 src/client/views/linking/LinkPopup.tsx             |   4 +-
 .../views/nodes/DataVizBox/components/TableBox.tsx |   2 +-
 src/client/views/nodes/DocumentLinksButton.tsx     |   6 +-
 src/client/views/nodes/DocumentView.tsx            |  43 +-
 src/client/views/nodes/KeyValuePair.tsx            |   4 +-
 src/client/views/nodes/LabelBox.tsx                |   4 +-
 src/client/views/nodes/LinkAnchorBox.tsx           |   4 +-
 src/client/views/nodes/LinkDocPreview.tsx          |   4 +-
 src/client/views/nodes/MapBox/MapBox.tsx           |   8 +-
 src/client/views/nodes/MapBox/MapBox2.tsx          |   8 +-
 src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx |   2 +-
 src/client/views/nodes/PDFBox.tsx                  |   4 +-
 src/client/views/nodes/QueryBox.scss               |   5 -
 src/client/views/nodes/QueryBox.tsx                |  38 --
 src/client/views/nodes/VideoBox.tsx                |   4 +-
 src/client/views/nodes/WebBox.tsx                  |   8 +-
 src/client/views/nodes/button/FontIconBox.tsx      |   2 +-
 .../views/nodes/formattedText/DashDocView.tsx      |   4 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx |  22 +-
 src/client/views/nodes/trails/PresBox.tsx          |  14 +-
 src/client/views/nodes/trails/PresElementBox.tsx   |  10 +-
 src/client/views/pdf/PDFViewer.tsx                 |  10 +-
 src/fields/Doc.ts                                  |  44 +-
 src/fields/documentSchemas.ts                      |  10 +-
 src/fields/util.ts                                 |   8 +-
 src/mobile/AudioUpload.tsx                         |  10 +-
 src/mobile/MobileInterface.tsx                     |   4 +-
 72 files changed, 740 insertions(+), 761 deletions(-)
 delete mode 100644 src/client/views/nodes/QueryBox.scss
 delete mode 100644 src/client/views/nodes/QueryBox.tsx

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index c1abd6e71..a91d5806c 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -110,18 +110,28 @@ class DocInfo extends FInfo {
     }
 }
 class DimInfo extends FInfo {
-    fieldType? = 'DimUnit';
+    fieldType? = 'enumeration';
     values? = [DimUnit.Pixel, DimUnit.Ratio];
-    readOnly = true;
+    readOnly = false;
 }
 class PEInfo extends FInfo {
-    fieldType? = 'pointerEvents';
+    fieldType? = 'enumeration';
     values? = ['all', 'none'];
-    readOnly = true;
+    readOnly = false;
 }
 class DAInfo extends FInfo {
-    fieldType? = 'dropActionType';
+    fieldType? = 'enumeration';
     values? = ['embed', 'copy', 'move', 'same', 'proto', 'none'];
+    readOnly = false;
+}
+class CTypeInfo extends FInfo {
+    fieldType? = 'enumeration';
+    values? = Array.from(Object.keys(CollectionViewType));
+    readOnly = false;
+}
+class DTypeInfo extends FInfo {
+    fieldType? = 'enumeration';
+    values? = Array.from(Object.keys(DocumentType));
     readOnly = true;
 }
 class DateInfo extends FInfo {
@@ -134,272 +144,267 @@ type STRt = StrInfo | string;
 type DOCt = DocInfo | Doc;
 type DIMt = DimInfo | typeof DimUnit.Pixel | typeof DimUnit.Ratio;
 type PEVt = PEInfo | 'none' | 'all';
+type COLLt = CTypeInfo | CollectionViewType;
 type DROPt = DAInfo | dropActionType;
 type DATEt = DateInfo | number;
+type DTYPEt = DTypeInfo | string;
 export class DocumentOptions {
+    // coordinate and dimensions depending on view
     x?: NUMt = new NumInfo('x coordinate of document in a freeform view');
     y?: NUMt = new NumInfo('y coordinage of document in a freeform view');
     z?: NUMt = new NumInfo('whether document is in overlay (1) or not (0)', false, [1, 0]);
-    isSystem?: BOOLt = new BoolInfo('is this a system created/owned doc', true);
-    type?: STRt = new StrInfo('type of document', true, Array.from(Object.keys(DocumentType)));
-    title?: string;
-    author_date?: DATEt = new DateInfo('date the document was created', true);
-    _dropAction?: DROPt = new DAInfo("what should happen to this document when it's dropped somewhere else");
-    allowOverlayDrop?: BOOLt = new BoolInfo('can documents be dropped onto this document without using dragging title bar or holding down embed key (ctrl)?', true);
-    childDropAction?: DROPt = new DAInfo("what should happen to the source document when it's dropped onto a child of a collection ");
-    targetDropAction?: DROPt = new DAInfo('what should happen to the source document when ??? ');
-    userColor?: STRt = new StrInfo('color associated with a Dash user (seen in header fields of shared documents)');
-    color?: STRt = new StrInfo('foreground color data doc');
-    backgroundColor?: STRt = new StrInfo('background color for data doc');
-    _layout_autoHeight?: BOOLt = new BoolInfo('whether document automatically resizes vertically to display contents');
-    _headerHeight?: NUMt = new NumInfo('height of document header used for displaying title');
-    _headerFontSize?: NUMt = new NumInfo('font size of header of custom notes');
-    _headerPointerEvents?: PEVt = new PEInfo('types of events the header of a custom text document can consume');
-    _freeform_panX?: NUMt = new NumInfo('horizontal pan location of a freeform view');
-    _freeform_panY?: NUMt = new NumInfo('vertical pan location of a freeform view');
+    _dimMagnitude?: NUMt = new NumInfo("magnitude of collectionMulti{row,col} element's width or height");
+    _dimUnit?: DIMt = new DimInfo("units of collectionMulti{row,col} element's width or height - 'px' or '*' for pixels or relative units");
+    lat?: NUMt = new NumInfo('latitude coordinate for map views');
+    lng?: NUMt = new NumInfo('longitude coordinate for map views');
+    _timecodeToShow?: NUMt = new NumInfo('the time that a document should be displayed (e.g., when an annotation shows up as a video plays)');
+    _timecodeToHide?: NUMt = new NumInfo('the time that a document should be hidden');
     _width?: NUMt = new NumInfo('displayed width of a document');
     _height?: NUMt = new NumInfo('displayed height of document');
     data_nativeWidth?: NUMt = new NumInfo('native width of data field contents (e.g., the pixel width of an image)');
     data_nativeHeight?: NUMt = new NumInfo('native height of data field contents (e.g., the pixel height of an image)');
+    linearBtnWidth?: NUMt = new NumInfo('unexpanded width of a linear menu button (button "width" changes when it expands)');
     _nativeWidth?: NUMt = new NumInfo('native width of document contents (e.g., the pixel width of an image)');
     _nativeHeight?: NUMt = new NumInfo('native height of document contents (e.g., the pixel height of an image)');
     _nativeDimModifiable?: BOOLt = new BoolInfo('native dimensions can be modified using document decoration reizers');
     _nativeHeightUnfrozen?: BOOLt = new BoolInfo('native height can be changed independent of width by dragging decoration resizers');
-    _dimMagnitude?: NUMt = new NumInfo("magnitude of collectionMulti{row,col} element's width or height");
-    _dimUnit?: DIMt = new DimInfo("units of collectionMulti{row,col} element's width or height - 'px' or '*' for pixels or relative units");
+
+    'acl-Public'?: string; // public permissions
+    '_acl-Public'?: string; // public permissions
+    type?: DTYPEt = new DTypeInfo('type of document', true);
+    _type_collection?: COLLt = new CTypeInfo('how collection is rendered'); // sub type of a collection
+    title?: STRt = new StrInfo('title of document');
+    caption?: RichTextField;
+    author?: string; // STRt = new StrInfo('creator of document'); // bcz: don't change this. Otherwise, the userDoc's field Infos will have a FieldInfo assigned to its author field which will render it unreadable
+    author_date?: DATEt = new DateInfo('date the document was created', true);
+    annotationOn?: DOCt = new DocInfo('document annotated by this document');
+    color?: STRt = new StrInfo('foreground color data doc');
+    hidden?: BOOLt = new BoolInfo('whether the document is not rendered by its collection');
+    backgroundColor?: STRt = new StrInfo('background color for data doc');
+    opacity?: NUMt = new NumInfo('document opacity');
+    viewTransitionTime?: NUMt = new NumInfo('transition duration for view parameters');
+    dontRegisterView?: BOOLt = new BoolInfo('are views of this document registered so that they can be found when following links, etc');
+    dontUndo?: BOOLt = new BoolInfo('whether button clicks should be undoable (true for Undo/Redo/and sidebar) AND whether modifications to document are undoable (true for linearview menu buttons to prevent open/close from entering undo stack)');
+    _headerHeight?: NUMt = new NumInfo('height of document header used for displaying title');
+    _headerFontSize?: NUMt = new NumInfo('font size of header of custom notes');
+    _headerPointerEvents?: PEVt = new PEInfo('types of events the header of a custom text document can consume');
+    _lockedPosition?: BOOLt = new BoolInfo("lock the x,y coordinates of the document so that it can't be dragged");
+    _lockedTransform?: BOOLt = new BoolInfo('lock the freeform_panx,freeform_pany and scale parameters of the document so that it be panned/zoomed');
+
+    layout?: string | Doc; // default layout string or template document
+    layout_keyValue?: STRt = new StrInfo('layout definition for showing keyValue view of document');
+    layout_explainer?: STRt = new StrInfo('explanation displayed at top of a collection to describe its purpose');
+    layout_headerButton?: DOCt = new DocInfo('the (button) Doc to display at the top of a collection.');
+    layout_disableBrushing?: BOOLt = new BoolInfo('whether to suppress border highlighting');
+    layout_unrendered?: BOOLt = new BoolInfo('denotes an annotation that is not rendered with a DocumentView (e.g, rtf/pdf text selections and links to scroll locations in web/pdf)');
+    layout_hideOpenButton?: BOOLt = new BoolInfo('whether to hide the open full screen button when selected');
+    layout_hideDocumentButtonBar?: BOOLt = new BoolInfo('whether to hide the document decorations lower button bar when selected');
+    layout_hideLinkAnchors?: BOOLt = new BoolInfo('suppresses link anchor dots from being displayed');
+    layout_hideAllLinks?: BOOLt = new BoolInfo('whether all individual blue anchor dots should be hidden');
+    layout_hideResizeHandles?: BOOLt = new BoolInfo('whether to hide the resize handles when selected');
+    layout_hideLinkButton?: BOOLt = new BoolInfo('whether the blue link counter button should be hidden');
+    layout_hideDecorationTitle?: BOOLt = new BoolInfo('whether to suppress the document decortations title when selected');
+    layout_borderRounding?: string;
+    layout_boxShadow?: string; // box-shadow css string OR "standard" to use dash standard box shadow
+    layout_maxAutoHeight?: NUMt = new NumInfo('maximum height for newly created (eg, from pasting) text documents');
+    _layout_autoHeight?: BOOLt = new BoolInfo('whether document automatically resizes vertically to display contents');
+    _layout_curPage?: NUMt = new NumInfo('current page of a PDF or other? paginated document');
+    _layout_currentTimecode?: NUMt = new NumInfo('the current timecode of a time-based document (e.g., current time of a video)  value is in seconds');
+    _layout_hideContextMenu?: BOOLt = new BoolInfo('whether the context menu can be shown');
     _layout_fitWidth?: BOOLt = new BoolInfo('whether document should scale its contents to fit its rendered width or not (e.g., for PDFviews)');
-    _layoutFitContentsToBox?: BOOLt = new BoolInfo('whether a freeformview should zoom/scale to create a shrinkwrapped view of its content');
-    _contentBounds?: List<number>; // the (forced) bounds of the document to display. format is: [left, top, right, bottom]
-    _lockedPosition?: boolean; // lock the x,y coordinates of the document so that it can't be dragged
-    _lockedTransform?: boolean; // lock the freeform_panx,freeform_pany and scale parameters of the document so that it be panned/zoomed
-    _followLinkToggle?: boolean; // whether document, when clicked, toggles display of its link target
+    _layout_fitContentsToBox?: BOOLt = new BoolInfo('whether a freeformview should zoom/scale to create a shrinkwrapped view of its content');
+    _layout_fieldKey?: STRt = new StrInfo('the field key containing the current layout definition');
+    _layout_enableAltContentUI?: BOOLt = new BoolInfo('whether to show alternate content button');
     _layout_showTitle?: string; // field name to display in header (:hover is an optional suffix)
-    _layout_altContentUI?: boolean; // whether to show alternate content button
-    _isLightbox?: boolean; // whether a collection acts as a lightbox by opening lightbox links by hiding all other documents in collection besides link target
+    _layout_showSidebar?: BOOLt = new BoolInfo('whether an annotationsidebar should be displayed for text docuemnts');
     _layout_showCaption?: string; // which field to display in the caption area.  leave empty to have no caption
-    _layoutScrollTop?: number; // scroll location for pdfs
-    _noAutoscroll?: boolean; // whether collections autoscroll when this item is dragged
-    _chromeHidden?: boolean; // whether the editing chrome for a document is hidden
-    _searchDoc?: boolean; // is this a search document (used to change UI for search results in schema view)
-    _forceActive?: boolean; // flag to handle pointer events when not selected (or otherwise active)
-    enableDragWhenActive?: boolean; // allow dragging even if document contentts are active (e.g., tree, groups)
-    _stayInCollection?: boolean; // whether the document should remain in its collection when someone tries to drag and drop it elsewhere
-    _raiseWhenDragged?: boolean; // whether a document is brought to front when dragged.
-    _hideContextMenu?: boolean; // whether the context menu can be shown
-    _type_collection?: string; // sub type of a collection
-    type_collection?: string; // sub type of a collection
-    _gridGap?: number; // gap between items in masonry view
-    freeform?: string; // placeholder just so that the key value pane has a divider to render for freeform view data
-    _freeform_scale?: number; // how much a freeform view has been scaled (zoomed)
-    _overflow?: string; // set overflow behavior
-    _xMargin?: number; // gap between left edge of document and start of masonry/stacking layouts
-    _yMargin?: number; // gap between top edge of dcoument and start of masonry/stacking layouts
-    _xPadding?: number;
-    _yPadding?: number;
-    _carousel_index?: number; // which item index the carousel viewer is showing
-    _layout_showSidebar?: boolean; //whether an annotationsidebar should be displayed for text docuemnts
+
+    _chromeHidden?: BOOLt = new BoolInfo('whether the editing chrome for a document is hidden');
+    _gridGap?: NUMt = new NumInfo('gap between items in masonry view');
+    _xMargin?: NUMt = new NumInfo('gap between left edge of document and start of masonry/stacking layouts');
+    _yMargin?: NUMt = new NumInfo('gap between top edge of dcoument and start of masonry/stacking layouts');
+    _xPadding?: NUMt = new NumInfo('x padding');
+    _yPadding?: NUMt = new NumInfo('y padding');
     _singleLine?: boolean; // whether label box is restricted to one line of text
     _createDocOnCR?: boolean; // whether carriage returns and tabs create new text documents
-    _minFontSize?: number; // minimum font size for labelBoxes
-    _maxFontSize?: number; // maximum font size for labelBoxes
-    _columnWidth?: number;
-    _columnsHideIfEmpty?: boolean; // whether stacking view column headings should be hidden
-    _text_fontSize?: string;
-    _text_fontFamily?: string;
-    _text_fontWeight?: string;
-    _pivotField?: string; // field key used to determine headings for sections in stacking, masonry, pivot views
-    _layout_curPage?: number; // current page of a PDF or other? paginated document
-    _layout_currentTimecode?: number; // the current timecode of a time-based document (e.g., current time of a video)  value is in seconds
-    _currentFrame?: number; // the current frame of a frame-based collection (e.g., progressive slide)
-    _timecodeToShow?: number; // the time that a document should be displayed (e.g., when an annotation shows up as a video plays)
-    _timecodeToHide?: number; // the time that a document should be hidden
-    _timelineLabel?: boolean; // whether the document exists on a timeline
+    _columnWidth?: NUMt = new NumInfo('width of table column');
+    _columnsHideIfEmpty?: BOOLt = new BoolInfo('whether stacking view column headings should be hidden');
     _caption_xMargin?: NUMt = new NumInfo('x margin of caption inside of a carousel collection', true);
     _caption_yMargin?: NUMt = new NumInfo('y margin of caption inside of a carousel collection', true);
     icon_nativeWidth?: NUMt = new NumInfo('native width of icon view', true);
     icon_nativeHeight?: NUMt = new NumInfo('native height of icon view', true);
-    dragFactory_count?: NUMt = new NumInfo('number of items created from a drag button (used for setting title with incrementing index)', true);
-    openFactoryLocation?: string; // an OpenWhere value to place the factory created document
-    openFactoryAsDelegate?: boolean; //
-    lat?: number;
-    lng?: number;
-    infoWindowOpen?: boolean;
-    author?: string;
-    _layout_fieldKey?: string;
-    fieldValues?: List<any>; // possible field values used by fieldInfos
-    fieldType?: string; // type of afield used by fieldInfos
-    layout_unrendered?: boolean; // denotes an annotation that is not rendered with a DocumentView (e.g, rtf/pdf text selections and links to scroll locations in web/pdf)
-    'acl-Public'?: string; // public permissions
-    '_acl-Public'?: string; // public permissions
-    version?: string; // version identifier for a document
-    label?: string;
-    hidden?: boolean;
-    _hidden?: boolean;
-    pointerEvents?: string; // pointer events that the documentview should have
-    mediaState?: string; // status of audio/video media document: "pendingRecording", "recording", "paused", "playing"
-    recording?: boolean; // whether WebCam is recording or not
-    autoPlayAnchors?: boolean; // whether to play audio/video when an anchor is clicked in a stackedTimeline.
-    dontPlayLinkOnSelect?: boolean; // whether an audio/video should start playing when a link is followed to it.
-    linkSource?: Doc; // the source document for a collection of backlinks
+    _text_fontSize?: string;
+    _text_fontFamily?: string;
+    _text_fontWeight?: string;
+    _pivotField?: string; // field key used to determine headings for sections in stacking, masonry, pivot views
+
+    infoWindowOpen?: BOOLt = new BoolInfo('whether info window corresponding to pin is open (on MapDocuments)');
+    _carousel_index?: NUMt = new NumInfo('which item index the carousel viewer is showing');
+    _label_minFontSize?: NUMt = new NumInfo('minimum font size for labelBoxes');
+    _label_maxFontSize?: NUMt = new NumInfo('maximum font size for labelBoxes');
+    stroke_width?: NUMt = new NumInfo('width of an ink stroke');
+    icon_label?: STRt = new StrInfo('label to use for a fontIcon doc (otherwise, the title is used)');
+    mediaState?: STRt = new StrInfo('status of audio/video media document: "pendingRecording", "recording", "paused", "playing"');
+    recording?: BOOLt = new BoolInfo('whether WebCam is recording or not');
+    autoPlayAnchors?: BOOLt = new BoolInfo('whether to play audio/video when an anchor is clicked in a stackedTimeline.');
+    dontPlayLinkOnSelect?: BOOLt = new BoolInfo('whether an audio/video should start playing when a link is followed to it.');
     updateContentsScript?: ScriptField; // reactive script invoked when viewing a document that can update contents of a collection (or do anything)
     toolTip?: string; // tooltip to display on hover
     toolType?: string; // type of pen tool
-    expertMode?: boolean; // something available only in expert (not novice) mode
+    expertMode?: BOOLt = new BoolInfo('something available only in expert (not novice) mode');
+
+    contentPointerEvents?: string; // pointer events allowed for content of a document view.  eg. set to "none" in menuSidebar for sharedDocs so that you can select a document, but not interact with its contents
     contextMenuFilters?: List<ScriptField>;
     contextMenuScripts?: List<ScriptField>;
     contextMenuLabels?: List<string>;
     contextMenuIcons?: List<string>;
-    defaultDoubleClick?: 'ignore' | 'default'; // ignore double clicks, or deafult (undefined) means open document full screen
-    waitForDoubleClickToClick?: 'always' | 'never' | 'default'; // whether a click function wait for double click to expire.  'default' undefined = wait only if there's a click handler, "never" = never wait, "always" = alway wait
-    dontUndo?: boolean; // whether button clicks should be undoable ( true for Undo/Redo/and sidebar) AND whether modifications to document are undoable (true for linearview menu buttons to prevent open/close from entering undo stack)
-    layout?: string | Doc; // default layout string for a document
-    contentPointerEvents?: string; // pointer events allowed for content of a document view.  eg. set to "none" in menuSidebar for sharedDocs so that you can select a document, but not interact with its contents
-    childLimitHeight?: number; // whether to limit the height of collection children.  0 - means  height can be no bigger than width
+    childFilters_boolean?: string;
+    childFilters?: List<string>;
+    childLimitHeight?: NUMt = new NumInfo('whether to limit the height of collection children.  0 - means  height can be no bigger than width');
     childLayoutTemplate?: Doc; // template for collection to use to render its children (see PresBox layout in tree view)
     childLayoutString?: string; // template string for collection to use to render its children
-    childDocumentsActive?: boolean; // whether child documents are active when parent is document active
-    childDontRegisterViews?: boolean;
-    childHideLinkButton?: boolean; // hide link buttons on all children
+    childDocumentsActive?: BOOLt = new BoolInfo('whether child documents are active when parent is document active');
+    childDontRegisterViews?: BOOLt = new BoolInfo('whether child document views should be registered so that they can be found when following links, etc');
+    childHideLinkButton?: BOOLt = new BoolInfo('hide link buttons on all children');
     childContextMenuFilters?: List<ScriptField>;
     childContextMenuScripts?: List<ScriptField>;
     childContextMenuLabels?: List<string>;
     childContextMenuIcons?: List<string>;
-    followLinkZoom?: boolean; // whether to zoom to the target of a link
-    layout_hideLinkButton?: boolean; // whether the blue link counter button should be hidden
-    disableDocBrushing?: boolean; // whether to suppress border highlighting
-    layout_hideDecorationTitle?: boolean;
-    hideOpenButton?: boolean;
-    layout_hideResizeHandles?: boolean;
-    hideDocumentButtonBar?: boolean;
-    hideAllLinks?: boolean; // whether all individual blue anchor dots should be hidden
-    isTemplateForField?: string; // the field key for which the containing document is a rendering template
-    isTemplateDoc?: boolean;
     targetScriptKey?: string; // where to write a template script (used by collections with click templates which need to target onClick, onDoubleClick, etc)
-    templates?: List<string>;
-    hero?: ImageField; // primary image that best represents a compound document (e.g., for a buxton device document that has multiple images)
-    caption?: RichTextField;
-    opacity?: number;
-    defaultBackgroundColor?: string;
-    _layout_autoMoveAnchors?: boolean; // whether link endpoint should move around the edges of a document to make shortest path to other link endpoint
-    layout_hideLinkAnchors?: boolean; // suppresses link anchor dots from being displayed
-    isFolder?: boolean;
-    lastFrame?: number; // the last frame of a frame-based collection (e.g., progressive slide)
-    activeFrame?: number; // the active frame of a document in a frame base collection
-    appearFrame?: number; // the frame in which the document appears
-    viewTransitionTime?: number; // transition duration for view parameters
-    presPanX?: number; // panX saved as a view spec
-    presPanY?: number; // panY saved as a view spec
-    presViewScale?: number; // viewScale saved as a view Spec
-    presTransition?: number; //the time taken for the transition TO a document
-    presDuration?: number; //the duration of the slide in presentation view
-    presZoomText?: boolean; // whether text anchors should shown in a larger box when following links to make them stand out
-    borderRounding?: string;
-    boxShadow?: string; // box-shadow css string OR "standard" to use dash standard box shadow
+
+    lastFrame?: NUMt = new NumInfo('the last frame of a frame-based collection (e.g., progressive slide)');
+    activeFrame?: NUMt = new NumInfo('the active frame of a document in a frame base collection');
+    appearFrame?: NUMt = new NumInfo('the frame in which the document appears');
+    _currentFrame?: NUMt = new NumInfo('the current frame of a frame-based collection (e.g., progressive slide)');
+
+    isSystem?: BOOLt = new BoolInfo('is this a system created/owned doc', true);
+    isBaseProto?: BOOLt = new BoolInfo('is doc a base level prototype for data documents as opposed to data documents which are prototypes for layout documents.  base protos are not cloned during a deep');
+    isTemplateForField?: string; // the field key for which the containing document is a rendering template
+    isTemplateDoc?: BOOLt = new BoolInfo('is the document a template for creating other documents');
+    isGroup?: BOOLt = new BoolInfo('should collection use a grouping UI behavior');
+    isFolder?: BOOLt = new BoolInfo('is document a tree view folder');
+    _isTimelineLabel?: BOOLt = new BoolInfo('is document a timeline label');
+    _isLightbox?: BOOLt = new BoolInfo('whether a collection acts as a lightbox by opening lightbox links by hiding all other documents in collection besides link target');
+
+    presPanX?: NUMt = new NumInfo('panX saved as a view spec');
+    presPanY?: NUMt = new NumInfo('panY saved as a view spec');
+    presViewScale?: NUMt = new NumInfo('viewScale saved as a view Spec');
+    presTransition?: NUMt = new NumInfo('the time taken for the transition TO a document');
+    presDuration?: NUMt = new NumInfo('the duration of the slide in presentation view');
+    presZoomText?: BOOLt = new BoolInfo('whether text anchors should shown in a larger box when following links to make them stand out');
+
     data?: any;
-    isBaseProto?: boolean; // this Doc is base level prototype for data documents as opposed to data documents which are prototypes for layout documents.  base protos are not cloned during a deep
-    dontRegisterView?: boolean;
-    lookupField?: ScriptField; // script that returns the value of a field. This script is passed the rootDoc, layoutDoc, field, and container of the document.  see PresBox.
+    data_useCors?: BOOLt = new BoolInfo('whether CORS protocol should be used for web page');
     columnHeaders?: List<SchemaHeaderField>; // headers for stacking views
     schemaHeaders?: List<SchemaHeaderField>; // headers for schema view
-    dockingConfig?: string;
-    annotationOn?: Doc;
-    followLinkToggle?: boolean;
-    isGroup?: boolean; // whether a collection should use a grouping UI behavior
-    _removeDropProperties?: List<string>; // list of properties that should be removed from a document when it is dropped.  e.g., a creator button may be forceActive to allow it be dragged, but the forceActive property can be removed from the dropped document
+    dockingConfig?: STRt = new StrInfo('configuration of golden layout windows (applies only if doc is rendered as a CollectionDockingView)');
+    icon?: string; // icon used by fonticonbox to render button
     noteType?: string;
-    // BACKGROUND GRID
+
+    // freeform properties
     _freeform_backgroundGrid?: boolean;
+    _freeform_scale?: NUMt = new NumInfo('how much a freeform view has been scaled (zoomed)');
+    _freeform_panX?: NUMt = new NumInfo('horizontal pan location of a freeform view');
+    _freeform_panY?: NUMt = new NumInfo('vertical pan location of a freeform view');
+    _freeform_noAutoPan?: BOOLt = new BoolInfo('disables autopanning when this item is dragged');
+    _freeform_noZoom?: BOOLt = new BoolInfo('disables zooming');
 
     //BUTTONS
     buttonText?: string;
-    iconShape?: string; // shapes of the fonticon border
     btnType?: string;
     btnList?: List<string>;
     docColorBtn?: string;
     userColorBtn?: string;
-    canClick?: string;
     script?: ScriptField;
-    numBtnMax?: number;
-    numBtnMin?: number;
+    numBtnMax?: NUMt = new NumInfo('maximum value of a number button');
+    numBtnMin?: NUMt = new NumInfo('minimum value of a number button');
     switchToggle?: boolean;
     badgeValue?: ScriptField;
 
     //LINEAR VIEW
-    linearViewIsExpanded?: boolean; // is linear view expanded
-    linearViewExpandable?: boolean; // can linear view be expanded
-    linearViewToggleButton?: string; // button to open close linear view group
-    linearViewSubMenu?: boolean;
-    linearBtnWidth?: number;
-    flexGap?: number; // Linear view flex gap
+    linearView_IsExpanded?: BOOLt = new BoolInfo('is linear view expanded');
+    linearView_Expandable?: BOOLt = new BoolInfo('can linear view be expanded');
+    linearView_SubMenu?: BOOLt = new BoolInfo('is doc a sub menu of more linear views');
+    flexGap?: NUMt = new NumInfo('Linear view flex gap');
     flexDirection?: 'unset' | 'row' | 'column' | 'row-reverse' | 'column-reverse';
 
-    layout_linkView?: Doc; // view template for a link document
-    layout_keyValue?: string; // view tempalte for key value docs
     link_description?: string; // added for links
     link_relationship?: string; // type of relatinoship a link represents
-    layout_linkDisplay?: boolean; // whether a link line should be dipslayed between the two link anchors
-    layout_linkDisplayArrow?: boolean; // whether to display link's directional arrowhead
+    link_displayLine?: BOOLt = new BoolInfo('whether a link line should be dipslayed between the two link anchors');
+    link_displayArrow?: BOOLt = new BoolInfo("whether to display link's directional arrowhead");
     link_anchor_1?: Doc;
     link_anchor_2?: Doc;
-    link_anchor_1_useLinkSmallAnchor?: boolean; // whether link_anchor_1 of a link should use a miniature anchor dot (as when the anchor is a text selection)
-    link_anchor_2_useLinkSmallAnchor?: boolean; // whether link_anchor_1 of a link should use a miniature anchor dot (as when the anchor is a text selection)
-    ignoreClick?: boolean;
+    link_autoMoveAnchors?: BOOLt = new BoolInfo('whether link endpoint should move around the edges of a document to make shortest path to other link endpoint');
+    link_anchor_1_useSmallAnchor?: BOOLt = new BoolInfo('whether link_anchor_1 of a link should use a miniature anchor dot (as when the anchor is a text selection)');
+    link_anchor_2_useSmallAnchor?: BOOLt = new BoolInfo('whether link_anchor_1 of a link should use a miniature anchor dot (as when the anchor is a text selection)');
+    link_relationshipList?: List<string>; // for storing different link relationships (when set by user in the link editor)
+    link_relationshipSizes?: List<number>; //stores number of links contained in each relationship
+    link_colorList?: List<string>; // colors of links corresponding to specific link relationships
+    followLinkZoom?: BOOLt = new BoolInfo('whether to zoom to the target of a link');
+    followLinkToggle?: BOOLt = new BoolInfo('whether target of link should be toggled on and off when following a link to it');
+    followLinkLocation?: STRt = new StrInfo('where to open link target when following link');
+    followLinkAnimEffect?: STRt = new StrInfo('animation effect triggered on target of link');
+    followLinkAnimDirection?: STRt = new StrInfo('direction modifier for animation effect');
+
+    ignoreClick?: BOOLt = new BoolInfo('whether clicks on document should be ignored');
     onClick?: ScriptField;
     onDoubleClick?: ScriptField;
     onChildClick?: ScriptField; // script given to children of a collection to execute when they are clicked
     onChildDoubleClick?: ScriptField; // script given to children of a collection to execute when they are double clicked
+    defaultDoubleClick?: 'ignore' | 'default'; // ignore double clicks, or deafult (undefined) means open document full screen
+    waitForDoubleClickToClick?: 'always' | 'never' | 'default'; // whether a click function wait for double click to expire.  'default' undefined = wait only if there's a click handler, "never" = never wait, "always" = alway wait
     onPointerDown?: ScriptField;
     onPointerUp?: ScriptField;
+    dragFactory_count?: NUMt = new NumInfo('number of items created from a drag button (used for setting title with incrementing index)', true);
+    openFactoryLocation?: string; // an OpenWhere value to place the factory created document
+    openFactoryAsDelegate?: BOOLt = new BoolInfo('create a delegate of the factory');
+    _forceActive?: BOOLt = new BoolInfo('flag to handle pointer events when not selected (or otherwise active)');
+    enableDragWhenActive?: BOOLt = new BoolInfo('allow dragging even if document contentts are active (e.g., tree, groups)');
+    _stayInCollection?: 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.');
+    allowOverlayDrop?: BOOLt = new BoolInfo('can documents be dropped onto this document without using dragging title bar or holding down embed key (ctrl)?', true);
+    childDropAction?: DROPt = new DAInfo("what should happen to the source document when it's dropped onto a child of a collection ");
+    targetDropAction?: DROPt = new DAInfo('what should happen to the source document when ??? ');
+    _dropAction?: DROPt = new DAInfo("what should happen to this document when it's dropped somewhere else");
+    _removeDropProperties?: List<string>; // list of properties that should be removed from a document when it is dropped.  e.g., a creator button may be forceActive to allow it be dragged, but the forceActive property can be removed from the dropped document
+    cloneFieldFilter?: List<string>; // fields not to copy when the document is clonedclipboard?: Doc;
     dropConverter?: ScriptField; // script to run when documents are dropped on this Document.
     dragFactory?: Doc; // document to create when dragging with a suitable onDragStart script
     clickFactory?: Doc; // document to create when clicking on a button with a suitable onClick script
     onDragStart?: ScriptField; //script to execute at start of drag operation --  e.g., when a "creator" button is dragged this script generates a different document to drop
-    cloneFieldFilter?: List<string>; // fields not to copy when the document is clonedclipboard?: Doc;
-    filterBoolean?: string;
-    data_useCors?: boolean;
-    icon?: string; // icon used by fonticonbox to render button
-    target?: Doc; // available for use in scripts as the primary target document
-    sourcePanel?: Doc; // panel to display in 'targetContainer' as the result of a button onClick script
-    targetContainer?: Doc; // document whose proto will be set to 'panel' as the result of a onClick click script
-    searchFileTypes?: List<string>; // file types allowed in a search query
-    stroke_width?: number;
-    freezeChildren?: string; // whether children are now allowed to be added and or removed from a collection
-    treeViewHideTitle?: boolean; // whether to hide the top document title of a tree view
-    treeViewHideUnrendered?: boolean; // tells tree view not to display documents that have an 'layout_unrendered' tag unless they also have a treeViewFieldKey tag (presBox)
-    treeViewHideHeaderIfTemplate?: boolean; // whether to hide the header for a document in a tree view only if a childLayoutTemplate is provided (presBox)
-    treeViewHideHeader?: boolean; // whether to hide the header for a document in a tree view
-    treeViewHideHeaderFields?: boolean; // whether to hide the drop down options for tree view items.
+    target?: Doc; // available for use in scripts.  used to provide a document parameter to the script (Note, this is a convenience entry since any field could be used for parameterizing a script)
+
+    treeViewHideTitle?: BOOLt = new BoolInfo('whether to hide the top document title of a tree view');
+    treeViewHideUnrendered?: BOOLt = new BoolInfo("tells tree view not to display documents that have an 'layout_unrendered' tag unless they also have a treeViewFieldKey tag (presBox)");
+    treeViewHideHeaderIfTemplate?: BOOLt = new BoolInfo('whether to hide the header for a document in a tree view only if a childLayoutTemplate is provided (presBox)');
+    treeViewHideHeader?: BOOLt = new BoolInfo('whether to hide the header for a document in a tree view');
+    treeViewHideHeaderFields?: BOOLt = new BoolInfo('whether to hide the drop down options for tree view items.');
     treeViewChildDoubleClick?: ScriptField; //
-    // Action Button
-    buttonMenu?: boolean; // whether a action button should be displayed
-    buttonMenuDoc?: Doc;
-    explainer?: string;
-
-    treeViewOpenIsTransient?: boolean; // ignores the treeViewOpen Doc flag, allowing a treeViewItem's expand/collapse state to be independent of other views of the same document in the same or any other tree view
-    _treeViewOpen?: boolean; // whether this document is expanded in a tree view  (note: need _ and regular versions since this can be specified for both proto and layout docs)
-    treeViewOpen?: boolean; // whether this document is expanded in a tree view
+    treeViewOpenIsTransient?: BOOLt = new BoolInfo("ignores the treeViewOpen Doc flag, allowing a treeViewItem's expand/collapse state to be independent of other views of the same document in the same or any other tree view");
+    treeViewOpen?: BOOLt = new BoolInfo('whether this document is expanded in a tree view');
     treeViewExpandedView?: string; // which field/thing is displayed when this item is opened in tree view
-    treeViewExpandedViewLock?: boolean; // whether the expanded view can be changed
+    treeViewExpandedViewLock?: BOOLt = new BoolInfo('whether the expanded view can be changed');
     treeViewChecked?: ScriptField; // script to call when a tree view checkbox is checked
-    treeViewTruncateTitleWidth?: number;
-    treeViewHasOverlay?: boolean; // whether the treeview has an overlay for freeform annotations
+    treeViewTruncateTitleWidth?: NUMt = new NumInfo('maximum width of a treew view title before truncation');
+    treeViewHasOverlay?: BOOLt = new BoolInfo('whether the treeview has an overlay for freeform annotations');
     treeViewType?: string; // whether treeview is a Slide, file system, or (default) collection hierarchy
-    sidebarColor?: string; // background color of text sidebar
-    sidebarViewType?: string; // collection type of text sidebar
-    docMaxAutoHeight?: number; // maximum height for newly created (eg, from pasting) text documents
+    treeViewFreezeChildren?: STRt = new StrInfo('set (add, remove, add|remove) to disable adding, removing or both from collection');
+
+    sidebar_color?: string; // background color of text sidebar
+    sidebar_collectionType?: string; // collection type of text sidebar
+
     text?: string;
-    textTransform?: string; // is linear view expanded
-    letterSpacing?: string; // is linear view expanded
+    textTransform?: string;
+    letterSpacing?: string;
     iconTemplate?: string; // name of icon template style
-    selectedIndex?: number; // which item in a linear view has been selected using the "thumb doc" ui
+    selectedIndex?: NUMt = new NumInfo("which item in a linear view has been selected using the 'thumb doc' ui");
+
+    fieldValues?: List<any>; // possible values a field can have (used by FieldInfo's only)
+    fieldType?: string; // display type of a field, e.g. string, number, enumeration (used by FieldInfo's only)
+
     clipboard?: Doc;
-    searchQuery?: string; // for quersyBox
-    useLinkSmallAnchor?: boolean; // whether links to this document should use a miniature linkAnchorBox
-    border?: string; //for searchbox
     hoverBackgroundColor?: string; // background color of a label when hovered
-    link_relationshipList?: List<string>; // for storing different link relationships (when set by user in the link editor)
-    link_relationshipSizes?: List<number>; //stores number of links contained in each relationship
-    linkColorList?: List<string>; // colors of links corresponding to specific link relationships
+    userColor?: STRt = new StrInfo('color associated with a Dash user (seen in header fields of shared documents)');
 }
 export namespace Docs {
     export let newAccount: boolean = false;
@@ -986,7 +991,7 @@ export namespace Docs {
             I.layout = InkingStroke.LayoutString('stroke');
             I.layout_fitWidth = true;
             I.layout_hideDecorationTitle = true; // don't show title when selected
-            // I.hideOpenButton = true; // don't show open full screen button when selected
+            // I.layout_hideOpenButton = true; // don't show open full screen button when selected
             I.color = color;
             I.fillColor = fillColor;
             I.stroke = new InkField(points);
@@ -1088,7 +1093,12 @@ export namespace Docs {
         }
 
         export function PileDocument(documents: Array<Doc>, options: DocumentOptions, id?: string) {
-            return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _overflow: 'visible', enableDragWhenActive: true, _forceActive: true, _noAutoscroll: true, ...options, _type_collection: CollectionViewType.Pile }, id);
+            return InstanceFromProto(
+                Prototypes.get(DocumentType.COL),
+                new List(documents),
+                { enableDragWhenActive: true, _forceActive: true, _freeform_noZoom: true, _freeform_noAutoPan: true, ...options, _type_collection: CollectionViewType.Pile },
+                id
+            );
         }
 
         export function LinearDocument(documents: Array<Doc>, options: DocumentOptions, id?: string) {
@@ -1177,12 +1187,7 @@ export namespace Docs {
         }
 
         export function DockDocument(documents: Array<Doc>, config: string, options: DocumentOptions, id?: string) {
-            return InstanceFromProto(
-                Prototypes.get(DocumentType.COL),
-                new List(documents),
-                { freezeChildren: 'remove|add', ...options, type_collection: CollectionViewType.Docking, _type_collection: CollectionViewType.Docking, dockingConfig: config },
-                id
-            );
+            return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { treeViewFreezeChildren: 'remove|add', ...options, _type_collection: CollectionViewType.Docking, dockingConfig: config }, id);
         }
 
         export function DirectoryImportDocument(options: DocumentOptions = {}) {
@@ -1227,18 +1232,18 @@ export namespace Docs {
 export namespace DocUtils {
     /**
      * @param docs
-     * @param docFilters
-     * @param docRangeFilters
+     * @param childFilters
+     * @param childFiltersByRanges
      * @param parentCollection
-     * Given a list of docs and docFilters, @returns the list of Docs that match those filters
+     * Given a list of docs and childFilters, @returns the list of Docs that match those filters
      */
-    export function FilterDocs(childDocs: Doc[], docFilters: string[], docRangeFilters: string[], parentCollection?: Doc) {
-        if (!docFilters?.length && !docRangeFilters?.length) {
+    export function FilterDocs(childDocs: Doc[], childFilters: string[], childFiltersByRanges: string[], parentCollection?: Doc) {
+        if (!childFilters?.length && !childFiltersByRanges?.length) {
             return childDocs.filter(d => !d.cookies); // remove documents that need a cookie if there are no filters to provide one
         }
 
         const filterFacets: { [key: string]: { [value: string]: string } } = {}; // maps each filter key to an object with value=>modifier fields
-        docFilters.forEach(filter => {
+        childFilters.forEach(filter => {
             const fields = filter.split(':');
             const key = fields[0];
             const value = fields[1];
@@ -1249,7 +1254,7 @@ export namespace DocUtils {
             filterFacets[key][value] = modifiers;
         });
 
-        const filteredDocs = docFilters.length
+        const filteredDocs = childFilters.length
             ? childDocs.filter(d => {
                   if (d.z) return true;
                   // if the document needs a cookie but no filter provides the cookie, then the document does not pass the filter
@@ -1293,7 +1298,7 @@ export namespace DocUtils {
                                 return Field.toString(d[facetKey] as Field).includes(value);
                             });
                       // if we're ORing them together, the default return is false, and we return true for a doc if it satisfies any one set of criteria
-                      if (parentCollection?.filterBoolean === 'OR') {
+                      if (parentCollection?.childFilters_boolean === 'OR') {
                           if (satisfiesUnsetsFacets && satisfiesExistsFacets && satisfiesCheckFacets && !failsNotEqualFacets && satisfiesMatchFacets) return true;
                       }
                       // if we're ANDing them together, the default return is true, and we return false for a doc if it doesn't satisfy any set of criteria
@@ -1301,14 +1306,14 @@ export namespace DocUtils {
                           if (!satisfiesUnsetsFacets || !satisfiesExistsFacets || !satisfiesCheckFacets || failsNotEqualFacets || (matches.length && !satisfiesMatchFacets)) return false;
                       }
                   }
-                  return (parentCollection?.currentFilter as Doc)?.filterBoolean === 'OR' ? false : true;
+                  return (parentCollection?.currentFilter as Doc)?.childFilters_boolean === 'OR' ? false : true;
               })
             : childDocs;
         const rangeFilteredDocs = filteredDocs.filter(d => {
-            for (let i = 0; i < docRangeFilters.length; i += 3) {
-                const key = docRangeFilters[i];
-                const min = Number(docRangeFilters[i + 1]);
-                const max = Number(docRangeFilters[i + 2]);
+            for (let i = 0; i < childFiltersByRanges.length; i += 3) {
+                const key = childFiltersByRanges[i];
+                const min = Number(childFiltersByRanges[i + 1]);
+                const max = Number(childFiltersByRanges[i + 2]);
                 const val = typeof d[key] === 'string' ? (Number(StrCast(d[key])).toString() === StrCast(d[key]) ? Number(StrCast(d[key])) : undefined) : Cast(d[key], 'number', null);
                 if (val === undefined) {
                     //console.log("Should 'undefined' pass range filter or not?")
@@ -1325,11 +1330,11 @@ export namespace DocUtils {
         broadcastEvent && runInAction(() => (DocumentManager.Instance.RecordingEvent = DocumentManager.Instance.RecordingEvent + 1));
         return DocUtils.ActiveRecordings.map(audio => {
             const sourceDoc = getSourceDoc();
-            return sourceDoc && DocUtils.MakeLink(sourceDoc, audio.getAnchor(true) || audio.props.Document, { layout_linkDisplay: false, link_relationship: 'recording annotation:linked recording', link_description: 'recording timeline' });
+            return sourceDoc && DocUtils.MakeLink(sourceDoc, audio.getAnchor(true) || audio.props.Document, { link_displayLine: false, link_relationship: 'recording annotation:linked recording', link_description: 'recording timeline' });
         });
     }
 
-    export function MakeLink(source: Doc, target: Doc, linkSettings: { link_relationship?: string; link_description?: string; layout_linkDisplay?: boolean }, id?: string, showPopup?: number[]) {
+    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;
@@ -1370,15 +1375,15 @@ export namespace DocUtils {
                 source,
                 target,
                 {
-                    title: ComputedField.MakeFunction('generateLinkTitle(self)') as any,
-                    link_anchor_1_useLinkSmallAnchor: source.useLinkSmallAnchor ? true : undefined,
-                    link_anchor_2_useLinkSmallAnchor: target.useLinkSmallAnchor ? true : undefined,
                     'acl-Public': SharingPermissions.Augment,
                     '_acl-Public': SharingPermissions.Augment,
-                    layout_linkDisplay: linkSettings.layout_linkDisplay,
+                    title: ComputedField.MakeFunction('generateLinkTitle(self)') as any,
+                    link_anchor_1_useSmallAnchor: source.useSmallAnchor ? true : undefined,
+                    link_anchor_2_useSmallAnchor: target.useSmallAnchor ? true : undefined,
+                    link_displayLine: linkSettings.link_displayLine,
                     link_relationship: linkSettings.link_relationship,
                     link_description: linkSettings.link_description,
-                    _layout_autoMoveAnchors: true,
+                    link_autoMoveAnchors: true,
                     _layout_showCaption: 'link_description',
                     _layout_showTitle: 'link_relationship',
                 },
@@ -1706,14 +1711,14 @@ export namespace DocUtils {
         if (context && !hasContextAnchor && (context.type === DocumentType.VID || context.type === DocumentType.WEB || context.type === DocumentType.PDF || context.type === DocumentType.IMG)) {
             const pushpin = Docs.Create.FontIconDocument({
                 title: 'pushpin',
-                label: '',
+                icon_label: '',
                 annotationOn: Cast(doc.annotationOn, Doc, null),
                 followLinkToggle: true,
                 icon: 'map-pin',
                 x: Cast(doc.x, 'number', null),
                 y: Cast(doc.y, 'number', null),
                 backgroundColor: '#ACCEF7',
-                hideAllLinks: true,
+                layout_hideAllLinks: true,
                 _width: 15,
                 _height: 15,
                 _xPadding: 0,
@@ -1804,7 +1809,7 @@ export namespace DocUtils {
             _xMargin: noMargins ? 0 : undefined,
             _yMargin: noMargins ? 0 : undefined,
             annotationOn,
-            docMaxAutoHeight: maxHeight,
+            layout_maxAutoHeight: maxHeight,
             backgroundColor,
             _width: width || 200,
             _height: 35,
@@ -1812,7 +1817,7 @@ export namespace DocUtils {
             y: y,
             _layout_fitWidth: true,
             _layout_autoHeight: true,
-            _layout_altContentUI: BoolCast(Doc.UserDoc().defaultToFlashcards),
+            _layout_enableAltContentUI: BoolCast(Doc.UserDoc().defaultToFlashcards),
             title,
         });
         const template = Doc.UserDoc().defaultTextLayout;
@@ -1842,18 +1847,18 @@ export namespace DocUtils {
     }
 
     /**
-     * uploadFilesToDocs will take in an array of Files, and creates documents for the 
-     * new files. 
-     * 
+     * uploadFilesToDocs will take in an array of Files, and creates documents for the
+     * new files.
+     *
      * @param files an array of files that will be uploaded
      * @param options options to use while uploading
-     * @returns 
+     * @returns
      */
     export async function uploadFilesToDocs(files: File[], options: DocumentOptions) {
         const generatedDocuments: Doc[] = [];
 
-        // These files do not have overwriteDocs, so we do not set the guid and let the client generate one. 
-        const fileNoGuidPairs: Networking.FileGuidPair[] = files.map(file => ({file}));
+        // These files do not have overwriteDocs, so we do not set the guid and let the client generate one.
+        const fileNoGuidPairs: Networking.FileGuidPair[] = files.map(file => ({ file }));
 
         const upfiles = await Networking.UploadFilesToServer(fileNoGuidPairs);
         for (const {
@@ -1867,8 +1872,8 @@ export namespace DocUtils {
 
     export function uploadFileToDoc(file: File, options: DocumentOptions, overwriteDoc: Doc) {
         const generatedDocuments: Doc[] = [];
-        // Since this file has an overwriteDoc, we can set the client tracking guid to the overwriteDoc's guid. 
-        Networking.UploadFilesToServer([{file, guid: overwriteDoc[Id]}]).then(upfiles => {
+        // Since this file has an overwriteDoc, we can set the client tracking guid to the overwriteDoc's guid.
+        Networking.UploadFilesToServer([{ file, guid: overwriteDoc[Id] }]).then(upfiles => {
             const {
                 source: { name, type },
                 result,
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 6f6ac2d4a..59041862f 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -23,7 +23,7 @@ import { MainView } from "../views/MainView";
 import { ButtonType } from "../views/nodes/button/FontIconBox";
 import { OpenWhere } from "../views/nodes/DocumentView";
 import { OverlayView } from "../views/OverlayView";
-import { DragManager } from "./DragManager";
+import { DragManager, dropActionType } from "./DragManager";
 import { MakeTemplate } from "./DropConverter";
 import { FollowLinkScript } from "./LinkFollower";
 import { LinkManager } from "./LinkManager";
@@ -97,7 +97,7 @@ export class CurrentUserUtils {
 
         const reqdOpts:DocumentOptions = {
             title: "Experimental Tools", _xMargin: 0, _layout_showTitle: "title", _chromeHidden: true,
-            _stayInCollection: true, _hideContextMenu: true, _forceActive: true, isSystem: true,
+            _stayInCollection: true, _layout_hideContextMenu: true, _forceActive: true, isSystem: true,
             _layout_autoHeight: true, _width: 500, _height: 300, _layout_fitWidth: true, _columnWidth: 35, ignoreClick: true, _lockedPosition: true,
         };
         const reqdScripts = { dropConverter : "convertToButtons(dragData)" };
@@ -136,7 +136,7 @@ export class CurrentUserUtils {
         const reqdClickList = reqdTempOpts.map(opts => {
             const allOpts = {...reqdClickOpts, ...opts.opts};
             const clickDoc = tempClicks ? DocListCast(tempClicks.data).find(doc => doc.title === opts.opts.title): undefined;
-            return DocUtils.AssignOpts(clickDoc, allOpts) ?? MakeTemplate(Docs.Create.ScriptingDocument(ScriptField.MakeScript(opts.script, {heading:Doc.name, checked:"boolean", containingTreeView:Doc.name}), allOpts), true, opts.opts.title);
+            return DocUtils.AssignOpts(clickDoc, allOpts) ?? MakeTemplate(Docs.Create.ScriptingDocument(ScriptField.MakeScript(opts.script, {heading:Doc.name, checked:"boolean", containingTreeView:Doc.name}), allOpts), true, opts.opts.title?.toString());
         });
 
         const reqdOpts:DocumentOptions = {title: "click editor templates", _height:75, isSystem: true};
@@ -192,7 +192,7 @@ export class CurrentUserUtils {
                 {onClick:"deiconifyView(documentView)", onDoubleClick: "deiconifyViewToLightbox(documentView)", });
         };
         const labelBox = (opts: DocumentOptions, data?:string) => Docs.Create.LabelDocument({
-            textTransform: "unset", letterSpacing: "unset", _singleLine: false, _minFontSize: 14, _maxFontSize: 24, borderRounding: "5px",  _width: 150, _height: 70, _xPadding: 10, _yPadding: 10, ...opts
+            textTransform: "unset", letterSpacing: "unset", _singleLine: false, _label_minFontSize: 14, _label_maxFontSize: 24, layout_borderRounding: "5px",  _width: 150, _height: 70, _xPadding: 10, _yPadding: 10, ...opts
         });
         const imageBox = (opts: DocumentOptions, url?:string) => Docs.Create.ImageDocument(url ?? "http://www.cs.brown.edu/~bcz/noImage.png", { "icon_nativeWidth": 360 / 4, "icon_nativeHeight": 270 / 4, iconTemplate:DocumentType.IMG,  _width: 360 / 4, _height: 270 / 4,  _layout_showTitle: "title", ...opts });
         const fontBox = (opts:DocumentOptions, data?:string) => Docs.Create.FontIconDocument({ _nativeHeight: 30, _nativeWidth: 30, _width: 30, _height: 30, ...opts  });
@@ -260,10 +260,11 @@ export class CurrentUserUtils {
         const emptyThings:{key:string,  // the field name where the empty thing will be stored
                           opts:DocumentOptions,   // the document options that are required for the empty thing
                           funcs?:{[key:string]: any},  // computed fields that are rquired for the empth thing
+                          scripts?:{[key:string]: any},
                           creator:(opts:DocumentOptions)=> any // how to create the empty thing if it doesn't exist
               }[] = [
             {key: "Note",       creator: opts => Docs.Create.TextDocument("", opts),        opts: { _width: 200, _layout_autoHeight: true }},
-            {key: "Flashcard",  creator: opts => Docs.Create.TextDocument("", opts),        opts: { _width: 200, _layout_autoHeight: true, _layout_altContentUI: true}},
+            {key: "Flashcard",  creator: opts => Docs.Create.TextDocument("", opts),        opts: { _width: 200, _layout_autoHeight: true, _layout_enableAltContentUI: true}},
             {key: "Equation",   creator: opts => Docs.Create.EquationDocument(opts),        opts: { _width: 300, _height: 35, }},
             {key: "Noteboard",  creator: opts => Docs.Create.NoteTakingDocument([], opts),  opts: { _width: 250, _height: 200, _layout_fitWidth: true}},
             {key: "Simulation", creator: opts => Docs.Create.SimulationDocument(opts),      opts: { _width: 300, _height: 300, }},
@@ -274,11 +275,11 @@ export class CurrentUserUtils {
             {key: "Map",        creator: opts => Docs.Create.MapDocument([], opts),         opts: { _width: 800, _height: 600, _layout_fitWidth: true, _layout_showSidebar: true,  }},
             {key: "Screengrab", creator: Docs.Create.ScreenshotDocument,                    opts: { _width: 400, _height: 200 }},
             {key: "WebCam",     creator: opts => Docs.Create.WebCamDocument("", opts),      opts: { _width: 400, _height: 200, recording:true, isSystem: true, cloneFieldFilter: new List<string>(["isSystem"]) }},
-            {key: "Button",     creator: Docs.Create.ButtonDocument,                        opts: { _width: 150, _height: 50, _xPadding: 10, _yPadding: 10, onClick: FollowLinkScript()}},
+            {key: "Button",     creator: Docs.Create.ButtonDocument,                        opts: { _width: 150, _height: 50, _xPadding: 10, _yPadding: 10}, scripts: {onClick: FollowLinkScript()?.script.originalScript ?? ""}},
             {key: "Script",     creator: opts => Docs.Create.ScriptingDocument(null, opts), opts: { _width: 200, _height: 250, }},
             {key: "DataViz",    creator: opts => Docs.Create.DataVizDocument("/users/rz/Downloads/addresses.csv", opts),   opts: { _width: 300, _height: 300 }},
             {key: "Header",     creator: headerTemplate,                                    opts: { _width: 300, _height: 70, _headerPointerEvents: "all", _headerHeight: 12, _headerFontSize: 9, _layout_autoHeight: true, treeViewHideUnrendered: true}},
-            {key: "Trail",      creator: Docs.Create.PresDocument,                          opts: { _width: 400, _height: 30, _type_collection: CollectionViewType.Stacking, targetDropAction: "embed" as any, treeViewHideTitle: true, _layout_fitWidth:true, _chromeHidden: true, boxShadow: "0 0" }},
+            {key: "Trail",      creator: Docs.Create.PresDocument,                          opts: { _width: 400, _height: 30, _type_collection: CollectionViewType.Stacking, targetDropAction: "embed" as dropActionType, treeViewHideTitle: true, _layout_fitWidth:true, _chromeHidden: true, layout_boxShadow: "0 0" }},
             {key: "Tab",        creator: opts => Docs.Create.FreeformDocument([], opts),    opts: { _width: 500, _height: 800, _layout_fitWidth: true, _freeform_backgroundGrid: true, }},
             {key: "Slide",      creator: opts => Docs.Create.TreeDocument([], opts),        opts: { _width: 300, _height: 200, _type_collection: CollectionViewType.Tree, 
                                                                                                 treeViewHasOverlay: true, _text_fontSize: "20px", _layout_autoHeight: true, 
@@ -287,7 +288,7 @@ export class CurrentUserUtils {
                                                                                             }, funcs: {title: 'self.text?.Text'}},
             ];
 
-        emptyThings.forEach(thing => DocUtils.AssignDocField(doc, "empty"+thing.key, (opts) => thing.creator(opts), {...standardOps(thing.key), ...thing.opts}, undefined, undefined, thing.funcs));
+        emptyThings.forEach(thing => DocUtils.AssignDocField(doc, "empty"+thing.key, (opts) => thing.creator(opts), {...standardOps(thing.key), ...thing.opts}, undefined, thing.scripts, thing.funcs));
         
         return [
             { toolTip: "Tap or drag to create a note",            title: "Note", icon: "sticky-note",   dragFactory: doc.emptyNote as Doc,       clickFactory: DocCast(doc.emptyNote)},
@@ -321,7 +322,7 @@ export class CurrentUserUtils {
         const creatorBtns = CurrentUserUtils.creatorBtnDescriptors(doc).map((reqdOpts) => {
             const btn = dragCreatorDoc ? DocListCast(dragCreatorDoc.data).find(doc => doc.title === reqdOpts.title): undefined;
             const opts:DocumentOptions = {...OmitKeys(reqdOpts, ["funcs", "scripts", "backgroundColor"]).omit, 
-                _width: 35, _height: 35, _hideContextMenu: true, _stayInCollection: true, 
+                _width: 35, _height: 35, _layout_hideContextMenu: true, _stayInCollection: true, 
                 btnType: ButtonType.ToolButton, backgroundColor: reqdOpts.backgroundColor ?? Colors.DARK_GRAY, color: Colors.WHITE, isSystem: true,
                 _removeDropProperties: new List<string>(["_stayInCollection"]),
                 };
@@ -329,7 +330,7 @@ export class CurrentUserUtils {
         });
 
         const reqdOpts:DocumentOptions = {
-            title: "Basic Item Creators", _layout_showTitle: "title", _xMargin: 0, _stayInCollection: true, _hideContextMenu: true, _chromeHidden: true, isSystem: true,
+            title: "Basic Item Creators", _layout_showTitle: "title", _xMargin: 0, _stayInCollection: true, _layout_hideContextMenu: true, _chromeHidden: true, isSystem: true,
             _layout_autoHeight: true, _width: 500, _height: 300, _layout_fitWidth: true, _columnWidth: 40, ignoreClick: true, _lockedPosition: true, _forceActive: true,
              childDropAction: 'embed' 
         };
@@ -367,14 +368,14 @@ export class CurrentUserUtils {
             const btnDoc = myLeftSidebarMenu ? DocListCast(myLeftSidebarMenu.data).find(doc => doc.title === title) : undefined;
             const reqdBtnOpts:DocumentOptions = {
                 title, icon, target, btnType: ButtonType.MenuButton, isSystem: true, dontUndo: true, dontRegisterView: true,
-                _width: 60, _height: 60,  _stayInCollection: true, _hideContextMenu: true,
+                _width: 60, _height: 60,  _stayInCollection: true, _layout_hideContextMenu: true,
                 _removeDropProperties: new List<string>(["_stayInCollection"]),
             };
             return DocUtils.AssignScripts(DocUtils.AssignOpts(btnDoc, reqdBtnOpts) ?? Docs.Create.FontIconDocument(reqdBtnOpts), scripts, funcs);
         });
 
         const reqdStackOpts:DocumentOptions ={
-            title: "menuItemPanel", childDropAction: "same", backgroundColor: Colors.DARK_GRAY, boxShadow: "rgba(0,0,0,0)",  dontRegisterView: true, ignoreClick: true,
+            title: "menuItemPanel", childDropAction: "same", backgroundColor: Colors.DARK_GRAY, layout_boxShadow: "rgba(0,0,0,0)",  dontRegisterView: true, ignoreClick: true,
             _chromeHidden: true, _gridGap: 0, _yMargin: 0, _yPadding: 0, _xMargin: 0, _layout_autoHeight: false, _width: 60, _columnWidth: 60, _lockedPosition: true, isSystem: true,
         };
         return DocUtils.AssignDocField(doc, field, (opts, items) => Docs.Create.StackingDocument(items??[], opts), reqdStackOpts, menuBtns, { dropConverter: "convertToButtons(dragData)" });
@@ -413,14 +414,14 @@ export class CurrentUserUtils {
     static mobileButton = (opts: DocumentOptions, docs: Doc[]) => Docs.Create.MulticolumnDocument(docs, {
         ...opts,
          _nativeWidth: 900, _nativeHeight: 250, _width: 900, _height: 250, _yMargin: 15,
-        borderRounding: "5px", boxShadow: "0 0", isSystem: true
+        layout_borderRounding: "5px", layout_boxShadow: "0 0", isSystem: true
     }) as any as Doc
 
     // sets up the text container for the information contained within the mobile button
     static mobileTextContainer = (opts: DocumentOptions, docs: Doc[]) => Docs.Create.MultirowDocument(docs, {
         ...opts,
         _nativeWidth: 450, _nativeHeight: 250, _width: 450, _height: 250, _yMargin: 25,
-        backgroundColor: "rgba(0,0,0,0)", borderRounding: "0", boxShadow: "0 0", ignoreClick: true, isSystem: true
+        backgroundColor: "rgba(0,0,0,0)", layout_borderRounding: "0", layout_boxShadow: "0 0", ignoreClick: true, isSystem: true
     }) as any as Doc
 
     // Sets up the title of the button
@@ -458,7 +459,7 @@ export class CurrentUserUtils {
     static setupSearcher(doc: Doc, field:string) {
         return DocUtils.AssignDocField(doc, field, (opts, items) => Docs.Create.SearchDocument(opts), {
                 dontRegisterView: true, backgroundColor: "dimgray", ignoreClick: true, title: "Search Panel", isSystem: true, childDropAction: "embed", 
-                _lockedPosition: true, _type_collection: CollectionViewType.Schema, _searchDoc: true,  });
+                _lockedPosition: true, _type_collection: CollectionViewType.Schema  });
     }
 
     /// Initializes the panel of draggable tools that is opened from the left sidebar.
@@ -467,8 +468,8 @@ export class CurrentUserUtils {
         const creatorBtns = CurrentUserUtils.setupCreatorButtons(doc, DocListCast(myTools?.data)?.length ? DocListCast(myTools.data)[0]:undefined);
         const templateBtns = CurrentUserUtils.setupExperimentalTemplateButtons(doc,DocListCast(myTools?.data)?.length > 1 ? DocListCast(myTools.data)[1]:undefined);
         const reqdToolOps:DocumentOptions = {
-            title: "My Tools", isSystem: true, ignoreClick: true, boxShadow: "0 0",
-            _layout_showTitle: "title", _width: 500, _yMargin: 20, _lockedPosition: true, _forceActive: true, _stayInCollection: true, _hideContextMenu: true, _chromeHidden: true, 
+            title: "My Tools", isSystem: true, ignoreClick: true, layout_boxShadow: "0 0",
+            _layout_showTitle: "title", _width: 500, _yMargin: 20, _lockedPosition: true, _forceActive: true, _stayInCollection: true, _layout_hideContextMenu: true, _chromeHidden: true, 
         };
         return DocUtils.AssignDocField(doc, field, (opts, items) => Docs.Create.StackingDocument(items??[], opts), reqdToolOps, [creatorBtns, templateBtns]);
     }
@@ -480,10 +481,10 @@ export class CurrentUserUtils {
         const toggleDarkTheme = `this.colorScheme = this.colorScheme ? undefined : "${ColorScheme.Dark}"`;
         const newDashboard = `createNewDashboard()`;
 
-        const reqdBtnOpts:DocumentOptions = { _forceActive: true,  _width: 30, _height: 30, _stayInCollection: true, _hideContextMenu: true,
+        const reqdBtnOpts:DocumentOptions = { _forceActive: true,  _width: 30, _height: 30, _stayInCollection: true, _layout_hideContextMenu: true,
              title: "new dashboard", btnType: ButtonType.ClickButton, toolTip: "Create new dashboard", buttonText: "New trail", icon: "plus", isSystem: true };
         const reqdBtnScript = {onClick: newDashboard,}
-        const newDashboardButton = DocUtils.AssignScripts(DocUtils.AssignOpts(DocCast(myDashboards?.buttonMenuDoc), reqdBtnOpts) ?? Docs.Create.FontIconDocument(reqdBtnOpts), reqdBtnScript);
+        const newDashboardButton = DocUtils.AssignScripts(DocUtils.AssignOpts(DocCast(myDashboards?.layout_headerButton), reqdBtnOpts) ?? Docs.Create.FontIconDocument(reqdBtnOpts), reqdBtnScript);
        
         const contextMenuScripts = [/*newDashboard*/] as string[];
         const contextMenuLabels = [/*"Create New Dashboard"*/]  as string[];
@@ -493,15 +494,15 @@ export class CurrentUserUtils {
         const childContextMenuLabels =  ["Toggle Dark Theme", "Toggle Comic Mode", "Snapshot Dashboard", "Share Dashboard", "Remove Dashboard", "Reset Dashboard"];// entries must be kept in synch with childContextMenuScripts, childContextMenuIcons, and childContextMenuFilters
         const childContextMenuIcons = ["chalkboard", "tv", "camera", "users", "times", "trash"]; // entries must be kept in synch with childContextMenuScripts, childContextMenuLabels, and childContextMenuFilters
         const reqdOpts:DocumentOptions = {
-            title: "My Dashboards", childHideLinkButton: true, freezeChildren: "remove|add", treeViewHideTitle: true, boxShadow: "0 0", childDontRegisterViews: true,
+            title: "My Dashboards", childHideLinkButton: true, treeViewFreezeChildren: "remove|add", treeViewHideTitle: true, layout_boxShadow: "0 0", childDontRegisterViews: true,
             targetDropAction: "same", treeViewType: TreeViewType.fileSystem, isFolder: true, isSystem: true,  treeViewTruncateTitleWidth: 350, ignoreClick: true, 
-            buttonMenu: true, buttonMenuDoc: newDashboardButton, childDropAction: "embed",
+            layout_headerButton: newDashboardButton, childDropAction: "embed",
             _layout_showTitle: "title", _height: 400, _gridGap: 5, _forceActive: true, _lockedPosition: true,
             contextMenuLabels:new List<string>(contextMenuLabels),
             contextMenuIcons:new List<string>(contextMenuIcons),
             childContextMenuLabels:new List<string>(childContextMenuLabels),
             childContextMenuIcons:new List<string>(childContextMenuIcons),
-            explainer: "This is your collection of dashboards. A dashboard represents the tab configuration of your workspace. To manage documents as folders, go to the Files."
+            layout_explainer: "This is your collection of dashboards. A dashboard represents the tab configuration of your workspace. To manage documents as folders, go to the Files."
         };
         myDashboards = DocUtils.AssignDocField(doc, field, (opts) => Docs.Create.TreeDocument([], opts), reqdOpts);
         if (Cast(myDashboards.contextMenuScripts, listSpec(ScriptField), null)?.length !== contextMenuScripts.length) {
@@ -523,19 +524,19 @@ export class CurrentUserUtils {
         
         const newFolder = `TreeView_addNewFolder()`;
         const newFolderOpts: DocumentOptions = {
-            _forceActive: true, _stayInCollection: true, _hideContextMenu: true, _width: 30, _height: 30,
+            _forceActive: true, _stayInCollection: true, _layout_hideContextMenu: true, _width: 30, _height: 30,
             title: "New folder", btnType: ButtonType.ClickButton, toolTip: "Create new folder", buttonText: "New folder", icon: "folder-plus", isSystem: true
         };
         const newFolderScript = { onClick: newFolder};
-        const newFolderButton = DocUtils.AssignScripts(DocUtils.AssignOpts(DocCast(myFilesystem?.buttonMenuDoc), newFolderOpts) ?? Docs.Create.FontIconDocument(newFolderOpts), newFolderScript);
+        const newFolderButton = DocUtils.AssignScripts(DocUtils.AssignOpts(DocCast(myFilesystem?.layout_headerButton), newFolderOpts) ?? Docs.Create.FontIconDocument(newFolderOpts), newFolderScript);
         
         const reqdOpts:DocumentOptions = { _layout_showTitle: "title", _height: 100, _gridGap: 5, _forceActive: true, _lockedPosition: true, 
-            title: "My Documents", buttonMenu: true, buttonMenuDoc: newFolderButton, treeViewHideTitle: true, targetDropAction: "proto", isSystem: true,
-            isFolder: true, treeViewType: TreeViewType.fileSystem, childHideLinkButton: true, boxShadow: "0 0", childDontRegisterViews: true, 
+            title: "My Documents", layout_headerButton: newFolderButton, treeViewHideTitle: true, targetDropAction: "proto", isSystem: true,
+            isFolder: true, treeViewType: TreeViewType.fileSystem, childHideLinkButton: true, layout_boxShadow: "0 0", childDontRegisterViews: true, 
             treeViewTruncateTitleWidth: 350, ignoreClick: true, childDropAction: "embed",
             childContextMenuLabels: new List<string>(["Create new folder"]),
             childContextMenuIcons: new List<string>(["plus"]),
-            explainer: "This is your file manager where you can create folders to keep track of documents independently of your dashboard."
+            layout_explainer: "This is your file manager where you can create folders to keep track of documents independently of your dashboard."
         };
         myFilesystem = DocUtils.AssignDocField(doc, field, (opts, items) => Docs.Create.TreeDocument(items??[], opts), reqdOpts, [myFileOrphans]);
         const childContextMenuScripts = [newFolder];
@@ -548,21 +549,21 @@ export class CurrentUserUtils {
     /// initializes the panel displaying docs that have been recently closed
     static setupRecentlyClosed(doc: Doc, field:string) {
         const reqdOpts:DocumentOptions = { _layout_showTitle: "title", _lockedPosition: true, _gridGap: 5, _forceActive: true, 
-            title: "My Recently Closed", buttonMenu: true, childHideLinkButton: true, treeViewHideTitle: true, childDropAction: "embed", isSystem: true,
-            treeViewTruncateTitleWidth: 350, ignoreClick: true,  boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same",
+            title: "My Recently Closed", childHideLinkButton: true, treeViewHideTitle: true, childDropAction: "embed", isSystem: true,
+            treeViewTruncateTitleWidth: 350, ignoreClick: true,  layout_boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same",
             contextMenuLabels: new List<string>(["Empty recently closed"]),
             contextMenuIcons:new List<string>(["trash"]),
-            explainer: "Recently closed documents appear in this menu. They will only be deleted if you explicity empty this list."
+            layout_explainer: "Recently closed documents appear in this menu. They will only be deleted if you explicity empty this list."
         };
         const recentlyClosed = DocUtils.AssignDocField(doc, field, (opts) => Docs.Create.TreeDocument([], opts), reqdOpts);
 
         const clearAll = (target:string) => `getProto(${target}).data = new List([])`;
-        const clearBtnsOpts:DocumentOptions = { _width: 30, _height: 30, _forceActive: true, _stayInCollection: true, _hideContextMenu: true, 
+        const clearBtnsOpts:DocumentOptions = { _width: 30, _height: 30, _forceActive: true, _stayInCollection: true, _layout_hideContextMenu: true, 
             title: "Empty", target: recentlyClosed, btnType: ButtonType.ClickButton,  buttonText: "Empty", icon: "trash", isSystem: true,
             toolTip: "Empty recently closed",};
-        const clearDocsButton = DocUtils.AssignDocField(recentlyClosed, "clearDocsBtn", (opts) => Docs.Create.FontIconDocument(opts), clearBtnsOpts, undefined, {onClick: clearAll("self.target")});
+        DocUtils.AssignDocField(recentlyClosed, "layout_headerButton", (opts) => Docs.Create.FontIconDocument(opts), clearBtnsOpts, undefined, {onClick: clearAll("self.target")});
 
-        if (recentlyClosed.buttonMenuDoc !== clearDocsButton) Doc.GetProto(recentlyClosed).buttonMenuDoc = clearDocsButton;
+        //if (recentlyClosed.layout_headerButton !== clearDocsButton) Doc.GetProto(recentlyClosed).layout_headerButton = clearDocsButton;
         
         if (!Cast(recentlyClosed.contextMenuScripts, listSpec(ScriptField),null)?.find((script) => script.script.originalScript === clearAll("self"))) {
             recentlyClosed.contextMenuScripts = new List<ScriptField>([ScriptField.MakeScript(clearAll("self"))!])
@@ -574,7 +575,7 @@ export class CurrentUserUtils {
     static setupUserDocView(doc: Doc, field:string) {
         const reqdOpts:DocumentOptions = {
             _lockedPosition: true, _gridGap: 5, _forceActive: true, title: Doc.CurrentUserEmail +"-view",
-            boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", ignoreClick: true, isSystem: true,
+            layout_boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", ignoreClick: true, isSystem: true,
             treeViewHideTitle: true, treeViewTruncateTitleWidth: 350
         };
         if (!doc[field]) DocUtils.AssignOpts(doc, {treeViewOpen: true, treeViewExpandedView: "fields" });
@@ -582,14 +583,14 @@ export class CurrentUserUtils {
     }
 
     static linearButtonList = (opts: DocumentOptions, docs: Doc[]) => Docs.Create.LinearDocument(docs, {
-        ...opts, _gridGap: 0, _xMargin: 5, _yMargin: 5, boxShadow: "0 0", _forceActive: true,
+        ...opts, _gridGap: 0, _xMargin: 5, _yMargin: 5, layout_boxShadow: "0 0", _forceActive: true,
         dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }),
         _lockedPosition: true, isSystem: true, flexDirection: "row"
     })
 
     static createToolButton = (opts: DocumentOptions) => Docs.Create.FontIconDocument({
-        btnType: ButtonType.ToolButton, _forceActive: true, _hideContextMenu: true, 
-        _removeDropProperties: new List<string>([ "_hideContextMenu", "stayInCollection"]), 
+        btnType: ButtonType.ToolButton, _forceActive: true, _layout_hideContextMenu: true, 
+        _removeDropProperties: new List<string>([ "_layout_hideContextMenu", "stayInCollection"]), 
         _nativeWidth: 40, _nativeHeight: 40, _width: 40, _height: 40, isSystem: true, ...opts,
     })
 
@@ -609,8 +610,8 @@ export class CurrentUserUtils {
         ];
         const btns = btnDescs.map(desc => dockBtn({_width: 30, _height: 30, defaultDoubleClick: 'ignore', dontUndo: true, _stayInCollection: true, ...desc.opts}, desc.scripts));
         const dockBtnsReqdOpts:DocumentOptions = {
-            title: "docked buttons", _height: 40, flexGap: 0, boxShadow: "standard", childDropAction: 'embed',
-            childDontRegisterViews: true, linearViewIsExpanded: true, linearViewExpandable: true, ignoreClick: true
+            title: "docked buttons", _height: 40, flexGap: 0, layout_boxShadow: "standard", childDropAction: 'embed',
+            childDontRegisterViews: true, linearView_IsExpanded: true, linearView_Expandable: true, ignoreClick: true
         };
         reaction(() => UndoManager.redoStack.slice(), () => Doc.GetProto(btns.find(btn => btn.title === "redo")!).opacity = UndoManager.CanRedo() ? 1 : 0.4, { fireImmediately: true });
         reaction(() => UndoManager.undoStack.slice(), () => Doc.GetProto(btns.find(btn => btn.title === "undo")!).opacity = UndoManager.CanUndo() ? 1 : 0.4, { fireImmediately: true });
@@ -701,12 +702,12 @@ export class CurrentUserUtils {
             { title: "Back",    icon: "chevron-left",  toolTip: "Prev Animation Frame", btnType: ButtonType.ClickButton,         expertMode: true,  toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(self.toolType, self.expertMode)'}, width: 20,  scripts: { onClick: 'prevKeyFrame(_readOnly_)'}},
             { title: "Num", icon:"",toolTip: "Frame Number (click to toggle edit mode)",btnType: ButtonType.TextButton,          expertMode: true,  toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(self.toolType, self.expertMode)', buttonText: 'selectedDocs()?.lastElement()?.currentFrame?.toString()'}, width: 20, scripts: { onClick: '{ return curKeyFrame(_readOnly_);}'}},
             { title: "Fwd",     icon: "chevron-right", toolTip: "Next Animation Frame", btnType: ButtonType.ClickButton,         expertMode: true,  toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(self.toolType, self.expertMode)'}, width: 20,  scripts: { onClick: 'nextKeyFrame(_readOnly_)'}},
-            { title: "Text",    icon: "Text",          toolTip: "Text functions",       subMenu: CurrentUserUtils.textTools(),   expertMode: false, toolType:DocumentType.RTF,            funcs: {                                                                             linearViewIsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Always available
-            { title: "Ink",     icon: "Ink",           toolTip: "Ink functions",        subMenu: CurrentUserUtils.inkTools(),    expertMode: false, toolType:DocumentType.INK,            funcs: {                                                                             linearViewIsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`}, scripts: { onClick: 'setInkToolDefaults()'} }, // Always available
-            { title: "Doc",     icon: "Doc",           toolTip: "Freeform Doc tools",   subMenu: CurrentUserUtils.freeTools(),   expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode, true)`, linearViewIsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Always available
-            { title: "View",    icon: "View",          toolTip: "View tools",           subMenu: CurrentUserUtils.viewTools(),   expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode)`, linearViewIsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Always available
-            { title: "Web",     icon: "Web",           toolTip: "Web functions",        subMenu: CurrentUserUtils.webTools(),    expertMode: false, toolType:DocumentType.WEB,            funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode)`, linearViewIsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Only when Web is selected
-            { title: "Schema",  icon: "Schema",linearBtnWidth:58,toolTip: "Schema functions",    subMenu: CurrentUserUtils.schemaTools(), expertMode: false, toolType:CollectionViewType.Schema,   funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode)`, linearViewIsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} } // Only when Schema is selected
+            { title: "Text",    icon: "Text",          toolTip: "Text functions",       subMenu: CurrentUserUtils.textTools(),   expertMode: false, toolType:DocumentType.RTF,            funcs: {                                                                             linearView_IsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Always available
+            { title: "Ink",     icon: "Ink",           toolTip: "Ink functions",        subMenu: CurrentUserUtils.inkTools(),    expertMode: false, toolType:DocumentType.INK,            funcs: {                                                                             linearView_IsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`}, scripts: { onClick: 'setInkToolDefaults()'} }, // Always available
+            { title: "Doc",     icon: "Doc",           toolTip: "Freeform Doc tools",   subMenu: CurrentUserUtils.freeTools(),   expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode, true)`, linearView_IsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Always available
+            { title: "View",    icon: "View",          toolTip: "View tools",           subMenu: CurrentUserUtils.viewTools(),   expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode)`, linearView_IsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Always available
+            { title: "Web",     icon: "Web",           toolTip: "Web functions",        subMenu: CurrentUserUtils.webTools(),    expertMode: false, toolType:DocumentType.WEB,            funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode)`, linearView_IsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Only when Web is selected
+            { title: "Schema",  icon: "Schema",linearBtnWidth:58,toolTip: "Schema functions",subMenu: CurrentUserUtils.schemaTools(), expertMode: false, toolType:CollectionViewType.Schema,   funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode)`, linearView_IsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} } // Only when Schema is selected
         ];
     }
 
@@ -719,7 +720,7 @@ export class CurrentUserUtils {
             _nativeWidth: params.width ?? 30, _width: params.width ?? 30,
             _height: 30, _nativeHeight: 30, linearBtnWidth: params.linearBtnWidth,
             toolType: params.toolType, expertMode: params.expertMode,
-            _stayInCollection: true, _hideContextMenu: true, _lockedPosition: true,
+            _stayInCollection: true, _layout_hideContextMenu: true, _lockedPosition: true,
             _removeDropProperties: new List<string>([ "_stayInCollection"]),
         };
         const reqdFuncs:{[key:string]:any} = {
@@ -731,7 +732,7 @@ export class CurrentUserUtils {
 
     /// Initializes all the default buttons for the top bar context menu
     static setupContextMenuButtons(doc: Doc, field="myContextMenuBtns") {
-        const reqdCtxtOpts:DocumentOptions = { title: "context menu buttons", dontUndo:true, flexGap: 0, childDropAction: 'embed', childDontRegisterViews: true,  linearViewIsExpanded: true, ignoreClick: true, linearViewExpandable: false, _height: 35 };
+        const reqdCtxtOpts:DocumentOptions = { title: "context menu buttons", dontUndo:true, flexGap: 0, childDropAction: 'embed', childDontRegisterViews: true,  linearView_IsExpanded: true, ignoreClick: true, linearView_Expandable: false, _height: 35 };
         const ctxtMenuBtnsDoc = DocUtils.AssignDocField(doc, field, (opts, items) => this.linearButtonList(opts, items??[]), reqdCtxtOpts, undefined);
         const ctxtMenuBtns = CurrentUserUtils.contextMenuTools().map(params => {
             const menuBtnDoc = DocListCast(ctxtMenuBtnsDoc?.data).find(doc => doc.title === params.title);
@@ -740,7 +741,7 @@ export class CurrentUserUtils {
             } else {
                 const reqdSubMenuOpts = { ...OmitKeys(params, ["scripts", "funcs", "subMenu"]).omit, dontUndo: true,
                     childDontRegisterViews: true, flexGap: 0, _height: 30, ignoreClick: params.scripts?.onClick ? false : true,
-                    linearViewSubMenu: true, linearViewExpandable: true, };
+                    linearView_SubMenu: true, linearView_Expandable: true, };
                 const items = params.subMenu?.map(sub =>
                     this.setupContextMenuButton(sub, DocListCast(menuBtnDoc?.data).find(doc => doc.title === sub.title))
                 );
@@ -793,8 +794,8 @@ export class CurrentUserUtils {
             "acl-Public": SharingPermissions.Augment, "_acl-Public": SharingPermissions.Augment,
             childDropAction: "embed", isSystem: true, contentPointerEvents: "all", childLimitHeight: 0, _yMargin: 0, _gridGap: 15, childDontRegisterViews:true,
             // NOTE: treeViewHideTitle & _layout_showTitle is for a TreeView's editable title, _layout_showTitle is for DocumentViews title bar
-            _layout_showTitle: "title", treeViewHideTitle: true, ignoreClick: true, _lockedPosition: true, boxShadow: "0 0", _chromeHidden: true, dontRegisterView: true, 
-            explainer: "This is where documents or dashboards that other users have shared with you will appear. To share a document or dashboard right click and select 'Share'"
+            _layout_showTitle: "title", treeViewHideTitle: true, ignoreClick: true, _lockedPosition: true, layout_boxShadow: "0 0", _chromeHidden: true, dontRegisterView: true, 
+            layout_explainer: "This is where documents or dashboards that other users have shared with you will appear. To share a document or dashboard right click and select 'Share'"
         };
         
         DocUtils.AssignDocField(doc, "mySharedDocs", opts => Docs.Create.TreeDocument([], opts, sharingDocumentId + "layout", sharingDocumentId), sharedDocOpts, undefined, sharedScripts);
@@ -803,17 +804,17 @@ export class CurrentUserUtils {
     /// Import option on the left side button panel 
     static setupImportSidebar(doc: Doc, field:string) {   
         const reqdOpts:DocumentOptions = {
-            title: "My Imports", _forceActive: true, buttonMenu: true, ignoreClick: true, _layout_showTitle: "title", 
-            _stayInCollection: true, _hideContextMenu: true, childLimitHeight: 0,
-            childDropAction: "copy", _layout_autoHeight: true, _yMargin: 50, _gridGap: 15, boxShadow: "0 0", _lockedPosition: true, isSystem: true, _chromeHidden: true,
-            dontRegisterView: true, explainer: "This is where documents that are Imported into Dash will go."
+            title: "My Imports", _forceActive: true, ignoreClick: true, _layout_showTitle: "title", 
+            _stayInCollection: true, _layout_hideContextMenu: true, childLimitHeight: 0,
+            childDropAction: "copy", _layout_autoHeight: true, _yMargin: 50, _gridGap: 15, layout_boxShadow: "0 0", _lockedPosition: true, isSystem: true, _chromeHidden: true,
+            dontRegisterView: true, layout_explainer: "This is where documents that are Imported into Dash will go."
         };
         const myImports = DocUtils.AssignDocField(doc, field, (opts) => Docs.Create.StackingDocument([], opts), reqdOpts);
     
         const reqdBtnOpts:DocumentOptions = { _forceActive: true, toolTip: "Import from computer",
-            _width: 30, _height: 30, _stayInCollection: true, _hideContextMenu: true, title: "Import", btnType: ButtonType.ClickButton, 
+            _width: 30, _height: 30, _stayInCollection: true, _layout_hideContextMenu: true, title: "Import", btnType: ButtonType.ClickButton, 
             buttonText: "Import", icon: "upload", isSystem: true };
-        DocUtils.AssignDocField(myImports, "buttonMenuDoc", (opts) => Docs.Create.FontIconDocument(opts), reqdBtnOpts, undefined, { onClick: "importDocument()" });
+        DocUtils.AssignDocField(myImports, "layout_headerButton", (opts) => Docs.Create.FontIconDocument(opts), reqdBtnOpts, undefined, { onClick: "importDocument()" });
         return myImports;
     }
     /// Updates the UserDoc to have all required fields, docs, etc.  No changes should need to be
@@ -850,7 +851,7 @@ export class CurrentUserUtils {
         doc.defaultAclPrivate ?? (doc.defaultAclPrivate = false);
         doc.savedFilters ?? (doc.savedFilters = new List<Doc>());
         doc.filterDocCount = 0;
-        doc.freezeChildren = "remove|add";
+        doc.treeViewFreezeChildren = "remove|add";
         this.setupLinkDocs(doc, linkDatabaseId);
         this.setupSharedDocs(doc, sharingDocumentId);  // sets up the right sidebar collection for mobile upload documents and sharing
         this.setupDefaultIconTemplates(doc);  // creates a set of icon templates triggered by the document deoration icon
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 7a88ca991..612f16ce9 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -189,7 +189,7 @@ export class DocumentManager {
         while (
             containerDocContext.length &&
             containerDocContext[0]?.embedContainer &&
-            DocCast(containerDocContext[0].embedContainer)?.type_collection !== CollectionViewType.Docking &&
+            DocCast(containerDocContext[0].embedContainer)?._type_collection !== CollectionViewType.Docking &&
             (includeExistingViews || !DocumentManager.Instance.getDocumentView(containerDocContext[0]))
         ) {
             containerDocContext = [Cast(containerDocContext[0].embedContainer, Doc, null), ...containerDocContext];
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index fb4a8985c..668de5408 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -517,7 +517,7 @@ export namespace DragManager {
 
             const target = document.elementFromPoint(e.x, e.y);
 
-            if (target && !Doc.UserDoc()._noAutoscroll && !options?.noAutoscroll && !dragData.draggedDocuments?.some((d: any) => d._noAutoscroll)) {
+            if (target && !Doc.UserDoc()._noAutoscroll && !options?.noAutoscroll && !dragData.draggedDocuments?.some((d: any) => d._freeform_noAutoPan)) {
                 const autoScrollHandler = () => {
                     target.dispatchEvent(
                         new CustomEvent<React.DragEvent>('dashDragAutoScroll', {
diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts
index 41c2fa889..dbb05917e 100644
--- a/src/client/util/LinkManager.ts
+++ b/src/client/util/LinkManager.ts
@@ -134,7 +134,7 @@ export class LinkManager {
     public createlink_relationshipLists = () => {
         //create new lists for link relations and their associated colors if the lists don't already exist
         !Doc.UserDoc().link_relationshipList && (Doc.UserDoc().link_relationshipList = new List<string>());
-        !Doc.UserDoc().linkColorList && (Doc.UserDoc().linkColorList = new List<string>());
+        !Doc.UserDoc().link_ColorList && (Doc.UserDoc().link_ColorList = new List<string>());
         !Doc.UserDoc().link_relationshipSizes && (Doc.UserDoc().link_relationshipSizes = new List<number>());
     };
 
diff --git a/src/client/util/TrackMovements.ts b/src/client/util/TrackMovements.ts
index f83b6af0e..0e56ee1bc 100644
--- a/src/client/util/TrackMovements.ts
+++ b/src/client/util/TrackMovements.ts
@@ -3,6 +3,7 @@ import { NumCast } from '../../fields/Types';
 import { Doc, DocListCast } from '../../fields/Doc';
 import { CollectionDockingView } from '../views/collections/CollectionDockingView';
 import { Id } from '../../fields/FieldSymbols';
+import { CollectionViewType } from '../documents/DocumentTypes';
 
 export type Movement = {
     time: number;
@@ -89,7 +90,7 @@ export class TrackMovements {
         if (this.recordingFFViews === null) return;
 
         // so that the size comparisons are correct, we must filter to only the FFViews
-        const isFFView = (doc: Doc) => doc && 'type_collection' in doc && doc.type_collection === 'freeform';
+        const isFFView = (doc: Doc) => doc && doc._type_collection === CollectionViewType.Freeform;
         const tabbedFFViews = new Set<Doc>();
         for (const DashDoc of tabbedDocs) {
             if (isFFView(DashDoc)) tabbedFFViews.add(DashDoc);
diff --git a/src/client/views/DashboardView.tsx b/src/client/views/DashboardView.tsx
index 94dd010c3..50cf2226e 100644
--- a/src/client/views/DashboardView.tsx
+++ b/src/client/views/DashboardView.tsx
@@ -390,7 +390,7 @@ export class DashboardView extends React.Component {
             _width: 30,
             _height: 30,
             _stayInCollection: true,
-            _hideContextMenu: true,
+            _layout_hideContextMenu: true,
             title: 'New trail',
             toolTip: 'Create new trail',
             btnType: ButtonType.ClickButton,
@@ -415,16 +415,15 @@ export class DashboardView extends React.Component {
             childDropAction: 'embed',
             treeViewTruncateTitleWidth: 150,
             ignoreClick: true,
-            buttonMenu: true,
-            buttonMenuDoc: myTrailsBtn,
+            layout_headerButton: myTrailsBtn,
             contextMenuIcons: new List<string>(['plus']),
             contextMenuLabels: new List<string>(['Create New Trail']),
             _lockedPosition: true,
-            boxShadow: '0 0',
+            layout_boxShadow: '0 0',
             childDontRegisterViews: true,
             targetDropAction: 'same',
             isSystem: true,
-            explainer: 'All of the trails that you have created will appear here.',
+            layout_explainer: 'All of the trails that you have created will appear here.',
         };
         const myTrails = DocUtils.AssignScripts(Docs.Create.TreeDocument([], reqdOpts), { treeViewChildDoubleClick: 'openPresentation(documentView.rootDoc)' });
         dashboardDoc.myTrails = new PrefetchProxy(myTrails);
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index 6fab4430d..db24229dc 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -128,8 +128,6 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps>()
 
         isAnyChildContentActive = () => this._isAnyChildContentActive;
 
-        lookupField = (field: string) => ScriptCast((this.layoutDoc as any).lookupField)?.script.run({ self: this.layoutDoc, data: this.rootDoc, field: field }).result;
-
         protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
 
         @computed public get annotationKey() {
diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index 547d844ca..35b0b22a8 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -589,7 +589,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
                         <LinkPopup
                             key="popup"
                             showPopup={this._showLinkPopup}
-                            linkCreated={link => (link.layout_linkDisplay = !IsFollowLinkScript(this.props.views().lastElement()?.rootDoc.onClick))}
+                            linkCreated={link => (link.link_displayLine = !IsFollowLinkScript(this.props.views().lastElement()?.rootDoc.onClick))}
                             linkCreateAnchor={() => this.props.views().lastElement()?.ComponentView?.getAnchor?.(true)}
                             linkFrom={() => this.props.views().lastElement()?.rootDoc}
                         />
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index e4d50b143..528b82e3e 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -332,7 +332,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
                         const docMax = Math.min(NumCast(doc.width) / 2, NumCast(doc.height) / 2);
                         const ratio = dist / maxDist;
                         const radius = Math.min(1, ratio) * docMax;
-                        doc.borderRounding = `${radius}px`;
+                        doc.layout_borderRounding = `${radius}px`;
                     });
                 return false;
             }, // moveEvent
@@ -588,7 +588,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
                     let dW = docwidth * (dWin / refWidth);
                     let dH = docheight * (dHin / refHeight);
                     const scale = docView.props.ScreenToLocalTransform().Scale;
-                    const modifyNativeDim = (e.ctrlKey || doc.layout_forceReflow) && doc.nativeDimModifiable && ((!dragBottom && !dragTop) || e.ctrlKey || doc.nativeHeightUnfrozen);
+                    const modifyNativeDim = (e.ctrlKey && doc.nativeDimModifiable) || (doc.layout_forceReflow && !dragBottom && !dragTop) || (doc.nativeHeightUnfrozen && (dragBottom || dragTop || e.ctrlKey));
                     if (nwidth && nheight) {
                         if (nwidth / nheight !== docwidth / docheight && !dragBottom && !dragTop) {
                             docheight = (nheight / nwidth) * docwidth;
@@ -636,7 +636,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
                                 }
                             }
                             if (!modifyNativeDim) {
-                                actualdH = Math.min((nheight / nwidth) * docwidth, actualdH);
+                                actualdH = (nheight / nwidth) * docwidth; //, actualdH);
                             }
                             doc._height = actualdH;
                         }
@@ -750,13 +750,13 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
         const hideDecorations = seldocview.props.hideDecorations || seldocview.rootDoc.hideDecorations;
         const hideResizers = hideDecorations || seldocview.props.hideResizeHandles || seldocview.rootDoc.layout_hideResizeHandles || this._isRounding || this._isRotating;
         const hideTitle = hideDecorations || seldocview.props.hideDecorationTitle || seldocview.rootDoc.layout_hideDecorationTitle || this._isRounding || this._isRotating;
-        const hideDocumentButtonBar = hideDecorations || seldocview.props.hideDocumentButtonBar || seldocview.rootDoc.hideDocumentButtonBar || this._isRounding || this._isRotating;
+        const hideDocumentButtonBar = hideDecorations || seldocview.props.hideDocumentButtonBar || seldocview.rootDoc.layout_hideDocumentButtonBar || this._isRounding || this._isRotating;
         // if multiple documents have been opened at the same time, then don't show open button
         const hideOpenButton =
             hideDecorations ||
             seldocview.props.hideOpenButton ||
-            seldocview.rootDoc.hideOpenButton ||
-            SelectionManager.Views().some(docView => docView.props.Document._stayInCollection || docView.props.Document.isGroup || docView.props.Document.hideOpenButton) ||
+            seldocview.rootDoc.layout_hideOpenButton ||
+            SelectionManager.Views().some(docView => docView.rootDoc._stayInCollection || docView.rootDoc.isGroup || docView.rootDoc.layout_hideOpenButton) ||
             this._isRounding ||
             this._isRotating;
         const hideDeleteButton =
@@ -767,7 +767,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
             seldocview.rootDoc.hideDeleteButton ||
             SelectionManager.Views().some(docView => {
                 const collectionAcl = docView.props.docViewPath()?.lastElement() ? GetEffectiveAcl(docView.props.docViewPath().lastElement().rootDoc[DocData]) : AclEdit;
-                return (docView.rootDoc.stayInCollection && !docView.rootDoc.timelineLabel) || (collectionAcl !== AclAdmin && collectionAcl !== AclEdit && GetEffectiveAcl(docView.rootDoc) !== AclAdmin);
+                return (docView.rootDoc.stayInCollection && !docView.rootDoc._isTimelineLabel) || (collectionAcl !== AclAdmin && collectionAcl !== AclEdit && GetEffectiveAcl(docView.rootDoc) !== AclAdmin);
             });
 
         const topBtn = (key: string, icon: string, pointerDown: undefined | ((e: React.PointerEvent) => void), click: undefined | ((e: any) => void), title: string) => (
@@ -796,7 +796,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
 
         // Radius constants
         const useRounding = seldocview.ComponentView instanceof ImageBox || seldocview.ComponentView instanceof FormattedTextBox || seldocview.ComponentView instanceof CollectionFreeFormView;
-        const borderRadius = numberValue(StrCast(seldocview.rootDoc.borderRounding));
+        const borderRadius = numberValue(StrCast(seldocview.rootDoc.layout_borderRounding));
         const docMax = Math.min(NumCast(seldocview.rootDoc.width) / 2, NumCast(seldocview.rootDoc.height) / 2);
         const maxDist = Math.min((this.Bounds.r - this.Bounds.x) / 2, (this.Bounds.b - this.Bounds.y) / 2);
         const radiusHandle = (borderRadius / docMax) * maxDist;
diff --git a/src/client/views/FilterPanel.tsx b/src/client/views/FilterPanel.tsx
index 53c1f1018..fe42628cd 100644
--- a/src/client/views/FilterPanel.tsx
+++ b/src/client/views/FilterPanel.tsx
@@ -64,7 +64,7 @@ export class FilterPanel extends React.Component<filterProps> {
      * The current attributes selected to filter based on
      */
     @computed get activeFilters() {
-        return StrListCast(this.targetDoc?._docFilters);
+        return StrListCast(this.targetDoc?._childFilters);
     }
 
     /**
@@ -108,8 +108,8 @@ export class FilterPanel extends React.Component<filterProps> {
     @observable _chosenFacets = new ObservableMap<string, 'text' | 'checkbox' | 'slider' | 'range'>();
     @computed get activeFacets() {
         const facets = new Map<string, 'text' | 'checkbox' | 'slider' | 'range'>(this._chosenFacets);
-        StrListCast(this.targetDoc?._docFilters).map(filter => facets.set(filter.split(':')[0], filter.split(':')[2] === 'match' ? 'text' : 'checkbox'));
-        setTimeout(() => StrListCast(this.targetDoc?._docFilters).map(action(filter => this._chosenFacets.set(filter.split(':')[0], filter.split(':')[2] === 'match' ? 'text' : 'checkbox'))));
+        StrListCast(this.targetDoc?._childFilters).map(filter => facets.set(filter.split(':')[0], filter.split(':')[2] === 'match' ? 'text' : 'checkbox'));
+        setTimeout(() => StrListCast(this.targetDoc?._childFilters).map(action(filter => this._chosenFacets.set(filter.split(':')[0], filter.split(':')[2] === 'match' ? 'text' : 'checkbox'))));
         return facets;
     }
     /**
@@ -174,7 +174,7 @@ export class FilterPanel extends React.Component<filterProps> {
                         <Select placeholder="Add a filter..." options={options} isMulti={false} onChange={val => this.facetClick((val as UserOptions).value)} onKeyDown={e => e.stopPropagation()} value={null} closeMenuOnSelect={true} />
                     </div>
                     <div className="filterBox-select-bool">
-                        <select className="filterBox-selection" onChange={action(e => this.targetDoc && (this.targetDoc._filterBoolean = (e.target as any).value))} defaultValue={StrCast(this.targetDoc?.filterBoolean)}>
+                        <select className="filterBox-selection" onChange={action(e => this.targetDoc && (this.targetDoc._childFilters_boolean = (e.target as any).value))} defaultValue={StrCast(this.targetDoc?.childFilters_boolean)}>
                             {['AND', 'OR'].map(bool => (
                                 <option value={bool} key={bool}>
                                     {bool}
@@ -202,7 +202,7 @@ export class FilterPanel extends React.Component<filterProps> {
                 return (
                     <input
                         placeholder={
-                            StrListCast(this.targetDoc._docFilters)
+                            StrListCast(this.targetDoc._childFilters)
                                 .find(filter => filter.split(':')[0] === facetHeader)
                                 ?.split(':')[1] ?? '-empty-'
                         }
@@ -218,7 +218,7 @@ export class FilterPanel extends React.Component<filterProps> {
                             <input
                                 style={{ width: 20, marginLeft: 20 }}
                                 checked={
-                                    StrListCast(this.targetDoc._docFilters)
+                                    StrListCast(this.targetDoc._childFilters)
                                         .find(filter => filter.split(':')[0] === facetHeader && filter.split(':')[1] == facetValue)
                                         ?.split(':')[2] === 'check'
                                 }
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index 141e99c66..0951bff22 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -140,7 +140,7 @@ export class GestureOverlay extends Touchable<GestureOverlayProps> {
                 title: 'buttons',
                 _layout_autoHeight: true,
                 _yMargin: 5,
-                linearViewIsExpanded: true,
+                linearView_IsExpanded: true,
                 backgroundColor: 'white',
                 isSystem: true,
             });
@@ -148,7 +148,7 @@ export class GestureOverlay extends Touchable<GestureOverlayProps> {
                 _width: 300,
                 _height: 25,
                 _layout_autoHeight: true,
-                linearViewIsExpanded: true,
+                linearView_IsExpanded: true,
                 flexDirection: 'column',
                 isSystem: true,
             });
@@ -1013,8 +1013,8 @@ export class GestureOverlay extends Touchable<GestureOverlayProps> {
                 focus={emptyFunction}
                 whenChildContentsActiveChanged={emptyFunction}
                 bringToFront={emptyFunction}
-                docRangeFilters={returnEmptyFilter}
-                docFilters={returnEmptyFilter}
+                childFiltersByRanges={returnEmptyFilter}
+                childFilters={returnEmptyFilter}
                 searchFilterDocs={returnEmptyDoclist}
             />
         );
diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx
index 1b309a6be..286d39943 100644
--- a/src/client/views/LightboxView.tsx
+++ b/src/client/views/LightboxView.tsx
@@ -43,7 +43,7 @@ export class LightboxView extends React.Component<LightboxViewProps> {
     @observable private static _layoutTemplateString: Opt<string>;
     @observable private static _doc: Opt<Doc>;
     @observable private static _docTarget: Opt<Doc>;
-    @observable private static _docFilters: string[] = []; // filters
+    @observable private static _childFilters: string[] = []; // filters
     private static _savedState: Opt<LightboxSavedState>;
     private static _history: Opt<{ doc: Doc; target?: Doc }[]> = [];
     @observable private static _future: Opt<Doc[]> = [];
@@ -58,7 +58,7 @@ export class LightboxView extends React.Component<LightboxViewProps> {
             this.LightboxDoc.layout_fieldKey = this._savedState.layout_fieldKey;
         }
         if (!doc) {
-            this._docFilters && (this._docFilters.length = 0);
+            this._childFilters && (this._childFilters.length = 0);
             this._future = this._history = [];
             Doc.ActiveTool = InkTool.None;
             MainView.Instance._exploreMode = false;
@@ -134,7 +134,7 @@ export class LightboxView extends React.Component<LightboxViewProps> {
     @action
     public static SetCookie(cookie: string) {
         if (this.LightboxDoc && cookie) {
-            this._docFilters = (f => (this._docFilters ? [this._docFilters.push(f) as any, this._docFilters][1] : [f]))(`cookies:${cookie}:provide`);
+            this._childFilters = (f => (this._childFilters ? [this._childFilters.push(f) as any, this._childFilters][1] : [f]))(`cookies:${cookie}:provide`);
         }
     }
     public static AddDocTab = (doc: Doc, location: OpenWhere, layoutTemplate?: Doc | string) => {
@@ -148,7 +148,7 @@ export class LightboxView extends React.Component<LightboxViewProps> {
             layoutTemplate
         );
     };
-    docFilters = () => LightboxView._docFilters || [];
+    childFilters = () => LightboxView._childFilters || [];
     addDocTab = LightboxView.AddDocTab;
     @action public static Next() {
         const doc = LightboxView._doc!;
@@ -261,8 +261,8 @@ export class LightboxView extends React.Component<LightboxViewProps> {
                             renderDepth={0}
                             rootSelected={returnTrue}
                             docViewPath={returnEmptyDoclist}
-                            docFilters={this.docFilters}
-                            docRangeFilters={returnEmptyFilter}
+                            childFilters={this.childFilters}
+                            childFiltersByRanges={returnEmptyFilter}
                             searchFilterDocs={returnEmptyDoclist}
                             addDocument={undefined}
                             removeDocument={undefined}
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 8e112dddb..b0e992cb6 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -608,8 +608,8 @@ export class MainView extends React.Component {
                     focus={emptyFunction}
                     whenChildContentsActiveChanged={emptyFunction}
                     bringToFront={emptyFunction}
-                    docFilters={returnEmptyFilter}
-                    docRangeFilters={returnEmptyFilter}
+                    childFilters={returnEmptyFilter}
+                    childFiltersByRanges={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
                 />
             </div>
@@ -637,8 +637,8 @@ export class MainView extends React.Component {
                     focus={emptyFunction}
                     whenChildContentsActiveChanged={emptyFunction}
                     bringToFront={emptyFunction}
-                    docFilters={returnEmptyFilter}
-                    docRangeFilters={returnEmptyFilter}
+                    childFilters={returnEmptyFilter}
+                    childFiltersByRanges={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
                     suppressSetHeight={true}
                     renderDepth={this._hideUI ? 0 : -1}
@@ -736,8 +736,8 @@ export class MainView extends React.Component {
                         focus={emptyFunction}
                         whenChildContentsActiveChanged={emptyFunction}
                         bringToFront={emptyFunction}
-                        docFilters={returnEmptyFilter}
-                        docRangeFilters={returnEmptyFilter}
+                        childFilters={returnEmptyFilter}
+                        childFiltersByRanges={returnEmptyFilter}
                         searchFilterDocs={returnEmptyDoclist}
                     />
                 </div>
@@ -767,8 +767,8 @@ export class MainView extends React.Component {
                     isContentActive={returnTrue}
                     whenChildContentsActiveChanged={emptyFunction}
                     bringToFront={emptyFunction}
-                    docFilters={returnEmptyFilter}
-                    docRangeFilters={returnEmptyFilter}
+                    childFilters={returnEmptyFilter}
+                    childFiltersByRanges={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
                     scriptContext={this}
                 />
@@ -903,8 +903,8 @@ export class MainView extends React.Component {
                     renderDepth={0}
                     focus={emptyFunction}
                     whenChildContentsActiveChanged={emptyFunction}
-                    docFilters={returnEmptyFilter}
-                    docRangeFilters={returnEmptyFilter}
+                    childFilters={returnEmptyFilter}
+                    childFiltersByRanges={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
                 />
                 {['watching', 'recording'].includes(String(this.userDoc?.presentationMode) ?? '') ? <div style={{ border: '.5rem solid green', padding: '5px' }}>{StrCast(this.userDoc?.presentationMode)}</div> : <></>}
diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx
index 6c36d39b9..a4a2c1df9 100644
--- a/src/client/views/MarqueeAnnotator.tsx
+++ b/src/client/views/MarqueeAnnotator.tsx
@@ -126,7 +126,7 @@ export class MarqueeAnnotator extends React.Component<MarqueeAnnotatorProps> {
                           if (!e.aborted && e.linkDocument) {
                               Doc.GetProto(e.linkDocument).link_relationship = 'cropped image';
                               Doc.GetProto(e.linkDocument).title = 'crop: ' + this.props.docView.rootDoc.title;
-                              Doc.GetProto(e.linkDocument).layout_linkDisplay = false;
+                              Doc.GetProto(e.linkDocument).link_displayLine = false;
                           }
                       },
                   });
diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx
index 59865cba3..339507f65 100644
--- a/src/client/views/OverlayView.tsx
+++ b/src/client/views/OverlayView.tsx
@@ -228,8 +228,8 @@ export class OverlayView extends React.Component {
                             docViewPath={returnEmptyDoclist}
                             addDocTab={DocumentViewInternal.addDocTabFunc}
                             pinToPres={emptyFunction}
-                            docFilters={returnEmptyFilter}
-                            docRangeFilters={returnEmptyFilter}
+                            childFilters={returnEmptyFilter}
+                            childFiltersByRanges={returnEmptyFilter}
                             searchFilterDocs={returnEmptyDoclist}
                         />
                     </div>
diff --git a/src/client/views/Palette.tsx b/src/client/views/Palette.tsx
index 3ad28c418..749eb08a2 100644
--- a/src/client/views/Palette.tsx
+++ b/src/client/views/Palette.tsx
@@ -56,8 +56,8 @@ export default class Palette extends React.Component<PaletteProps> {
                             styleProvider={returnEmptyString}
                             whenChildContentsActiveChanged={emptyFunction}
                             bringToFront={emptyFunction}
-                            docFilters={returnEmptyFilter}
-                            docRangeFilters={returnEmptyFilter}
+                            childFilters={returnEmptyFilter}
+                            childFiltersByRanges={returnEmptyFilter}
                             searchFilterDocs={returnEmptyDoclist}
                         />
                         <div className="palette-cover" style={{ transform: `translate(${Math.max(0, this._selectedIndex) * 50.75 + 23}px, 0px)` }}></div>
diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx
index 76828a576..11b89fd69 100644
--- a/src/client/views/PropertiesButtons.tsx
+++ b/src/client/views/PropertiesButtons.tsx
@@ -133,14 +133,14 @@ export class PropertiesButtons extends React.Component<{}, {}> {
                     const containerDoc = dv.rootDoc;
                     //containerDoc.followAllLinks =
                     // containerDoc.noShadow =
-                    // containerDoc.disableDocBrushing =
+                    // containerDoc.layout_disableBrushing =
                     // containerDoc._forceActive =
                     //containerDoc._freeform_fitContentsToBox =
                     containerDoc._isLightbox = !containerDoc._isLightbox;
                     //containerDoc._xPadding = containerDoc._yPadding = containerDoc._isLightbox ? 10 : undefined;
                     const containerContents = DocListCast(dv.dataDoc[dv.props.fieldKey ?? Doc.LayoutFieldKey(containerDoc)]);
                     //dv.rootDoc.onClick = ScriptField.MakeScript('{self.data = undefined; documentView.select(false)}', { documentView: 'any' });
-                    containerContents.forEach(doc => LinkManager.Links(doc).forEach(link => (link.layout_linkDisplay = false)));
+                    containerContents.forEach(doc => LinkManager.Links(doc).forEach(link => (link.link_displayLine = false)));
                 });
             }
         );
diff --git a/src/client/views/PropertiesDocBacklinksSelector.tsx b/src/client/views/PropertiesDocBacklinksSelector.tsx
index 7b21629da..3e69bcba6 100644
--- a/src/client/views/PropertiesDocBacklinksSelector.tsx
+++ b/src/client/views/PropertiesDocBacklinksSelector.tsx
@@ -19,8 +19,8 @@ type PropertiesDocBacklinksSelectorProps = {
 @observer
 export class PropertiesDocBacklinksSelector extends React.Component<PropertiesDocBacklinksSelectorProps> {
     getOnClick = (link: Doc) => {
-        const linkSource = this.props.Document;
-        const other = LinkManager.getOppositeAnchor(link, linkSource);
+        const linkAnchor = this.props.Document;
+        const other = LinkManager.getOppositeAnchor(link, linkAnchor);
         const otherdoc = !other ? undefined : other.annotationOn && other.type !== DocumentType.RTF ? Cast(other.annotationOn, Doc, null) : other;
 
         if (otherdoc) {
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 00e077f96..1f2e21dd5 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -276,8 +276,8 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                         PanelHeight={panelHeight}
                         focus={emptyFunction}
                         ScreenToLocalTransform={this.getTransform}
-                        docFilters={returnEmptyFilter}
-                        docRangeFilters={returnEmptyFilter}
+                        childFilters={returnEmptyFilter}
+                        childFiltersByRanges={returnEmptyFilter}
                         searchFilterDocs={returnEmptyDoclist}
                         addDocument={returnFalse}
                         moveDocument={undefined}
@@ -941,26 +941,26 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     }
 
     /**
-     * Updates this.filterDoc's currentFilter and saves the docFilters on the currentFilter
+     * Updates this.filterDoc's currentFilter and saves the childFilters on the currentFilter
      */
     updateFilterDoc = (doc: Doc) => {
         if (this.selectedDoc) {
             if (doc === this.selectedDoc.currentFilter) return; // causes problems if you try to reapply the same doc
-            const savedDocFilters = doc._docFiltersList;
-            const currentDocFilters = this.selectedDoc._docFilters;
-            this.selectedDoc._docFilters = new List<string>();
-            (this.selectedDoc.currentFilter as Doc)._docFiltersList = currentDocFilters;
+            const savedDocFilters = doc._childFiltersList;
+            const currentDocFilters = this.selectedDoc._childFilters;
+            this.selectedDoc._childFilters = new List<string>();
+            (this.selectedDoc.currentFilter as Doc)._childFiltersList = currentDocFilters;
             this.selectedDoc.currentFilter = doc;
-            doc._docFiltersList = new List<string>();
-            this.selectedDoc._docFilters = savedDocFilters;
+            doc._childFiltersList = new List<string>();
+            this.selectedDoc._childFilters = savedDocFilters;
 
-            const savedDocRangeFilters = doc._docRangeFiltersList;
-            const currentDocRangeFilters = this.selectedDoc._docRangeFilters;
-            this.selectedDoc._docRangeFilters = new List<string>();
-            (this.selectedDoc.currentFilter as Doc)._docRangeFiltersList = currentDocRangeFilters;
+            const savedDocRangeFilters = doc._childFiltersByRangesList;
+            const currentDocRangeFilters = this.selectedDoc._childFiltersByRanges;
+            this.selectedDoc._childFiltersByRanges = new List<string>();
+            (this.selectedDoc.currentFilter as Doc)._childFiltersByRangesList = currentDocRangeFilters;
             this.selectedDoc.currentFilter = doc;
-            doc._docRangeFiltersList = new List<string>();
-            this.selectedDoc._docRangeFilters = savedDocRangeFilters;
+            doc._childFiltersByRangesList = new List<string>();
+            this.selectedDoc._childFiltersByRanges = savedDocRangeFilters;
         }
     };
 
@@ -1117,7 +1117,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
             Doc.GetProto(LinkManager.currentLink).link_relationship = value;
             const linkRelationshipList = StrListCast(Doc.UserDoc().link_relationshipList);
             const linkRelationshipSizes = NumListCast(Doc.UserDoc().link_relationshipSizes);
-            const linkColorList = StrListCast(Doc.UserDoc().linkColorList);
+            const linkColorList = StrListCast(Doc.UserDoc().link_ColorList);
 
             // if the relationship does not exist in the list, add it and a corresponding unique randomly generated color
             if (!linkRelationshipList?.includes(value)) {
@@ -1328,8 +1328,8 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                                     <div className="propertiesView-input inline">
                                         <p>Show link</p>
                                         <button
-                                            style={{ background: !LinkManager.currentLink?.layout_linkDisplay ? '' : '#4476f7', borderRadius: 3 }}
-                                            onPointerDown={e => this.toggleLinkProp(e, 'layout_linkDisplay')}
+                                            style={{ background: !LinkManager.currentLink?.link_displayLine ? '' : '#4476f7', borderRadius: 3 }}
+                                            onPointerDown={e => this.toggleLinkProp(e, 'link_displayLine')}
                                             onClick={e => e.stopPropagation()}
                                             className="propertiesButton">
                                             <FontAwesomeIcon className="fa-icon" icon={faArrowRight as IconLookup} size="lg" />
@@ -1338,8 +1338,8 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                                     <div className="propertiesView-input inline" style={{ marginLeft: 10 }}>
                                         <p>Auto-move anchors</p>
                                         <button
-                                            style={{ background: !LinkManager.currentLink?.layout_autoMoveAnchors ? '' : '#4476f7', borderRadius: 3 }}
-                                            onPointerDown={e => this.toggleLinkProp(e, 'layout_autoMoveAnchors')}
+                                            style={{ background: !LinkManager.currentLink?.link_autoMoveAnchors ? '' : '#4476f7', borderRadius: 3 }}
+                                            onPointerDown={e => this.toggleLinkProp(e, 'link_autoMoveAnchors')}
                                             onClick={e => e.stopPropagation()}
                                             className="propertiesButton">
                                             <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
@@ -1348,8 +1348,8 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                                     <div className="propertiesView-input inline" style={{ marginLeft: 10 }}>
                                         <p>Display arrow</p>
                                         <button
-                                            style={{ background: !LinkManager.currentLink?.layout_linkDisplayArrow ? '' : '#4476f7', borderRadius: 3 }}
-                                            onPointerDown={e => this.toggleLinkProp(e, 'layout_linkDisplayArrow')}
+                                            style={{ background: !LinkManager.currentLink?.link_displayArrow ? '' : '#4476f7', borderRadius: 3 }}
+                                            onPointerDown={e => this.toggleLinkProp(e, 'link_displayArrow')}
                                             onClick={e => e.stopPropagation()}
                                             className="propertiesButton">
                                             <FontAwesomeIcon className="fa-icon" icon={faArrowRight as IconLookup} size="lg" />
diff --git a/src/client/views/SidebarAnnos.tsx b/src/client/views/SidebarAnnos.tsx
index 498e2ccba..db273cc88 100644
--- a/src/client/views/SidebarAnnos.tsx
+++ b/src/client/views/SidebarAnnos.tsx
@@ -63,11 +63,11 @@ export class SidebarAnnos extends React.Component<FieldViewProps & ExtraProps> {
         return Array.from(keys.keys()).sort();
     }
     get filtersKey() {
-        return '_' + this.sidebarKey + '_docFilters';
+        return '_' + this.sidebarKey + '_childFilters';
     }
 
     anchorMenuClick = (anchor: Doc) => {
-        const startup = StrListCast(this.props.rootDoc.docFilters)
+        const startup = StrListCast(this.props.rootDoc.childFilters)
             .map(filter => filter.split(':')[0])
             .join(' ');
         const target = Docs.Create.TextDocument(startup, {
@@ -83,9 +83,9 @@ export class SidebarAnnos extends React.Component<FieldViewProps & ExtraProps> {
         FormattedTextBox.SelectOnLoad = target[Id];
         FormattedTextBox.DontSelectInitialText = true;
         const link = DocUtils.MakeLink(anchor, target, { link_relationship: 'inline comment:comment on' });
-        link && (link.layout_linkDisplay = false);
+        link && (link.link_displayLine = false);
 
-        const taggedContent = this.docFilters()
+        const taggedContent = this.childFilters()
             .filter(data => data.split(':')[0])
             .map(data => {
                 const key = data.split(':')[0];
@@ -177,7 +177,7 @@ export class SidebarAnnos extends React.Component<FieldViewProps & ExtraProps> {
     addDocument = (doc: Doc | Doc[]) => this.props.sidebarAddDocument(doc, this.sidebarKey);
     moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean) => this.props.moveDocument(doc, targetCollection, addDocument, this.sidebarKey);
     removeDocument = (doc: Doc | Doc[]) => this.props.removeDocument(doc, this.sidebarKey);
-    docFilters = () => [...StrListCast(this.props.layoutDoc._docFilters), ...StrListCast(this.props.layoutDoc[this.filtersKey])];
+    childFilters = () => [...StrListCast(this.props.layoutDoc._childFilters), ...StrListCast(this.props.layoutDoc[this.filtersKey])];
     layout_showTitle = () => 'title';
     setHeightCallback = (height: number) => this.props.setHeight?.(height + this.filtersHeight());
     sortByLinkAnchorY = (a: Doc, b: Doc) => {
@@ -238,7 +238,7 @@ export class SidebarAnnos extends React.Component<FieldViewProps & ExtraProps> {
                         ref={this._stackRef}
                         PanelHeight={this.panelHeight}
                         PanelWidth={this.panelWidth}
-                        docFilters={this.docFilters}
+                        childFilters={this.childFilters}
                         sortFunc={this.sortByLinkAnchorY}
                         setHeight={this.setHeightCallback}
                         isAnnotationOverlay={false}
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index cf0177f4b..9199bf931 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -115,7 +115,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
             allSorts[TreeSort.None] = { color: 'darkgray', label: '\u00A0\u00A0\u00A0' };
             return allSorts;
         case StyleProp.Highlighting:
-            if (doc && !doc.disableDocBrushing && !props?.disableDocBrushing) {
+            if (doc && !doc.layout_disableBrushing && !props?.disableBrushing) {
                 const selected = SelectionManager.Views().some(dv => dv.rootDoc === doc);
                 const highlightIndex = Doc.isBrushedHighlightedDegree(doc) || (selected ? Doc.DocBrushStatus.selfBrushed : 0);
                 const highlightColor = ['transparent', 'rgb(68, 118, 247)', selected ? 'black' : 'rgb(68, 118, 247)', 'orange', 'lightBlue'][highlightIndex];
@@ -166,7 +166,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
             if (!backColor) return undefined;
             return lightOrDark(backColor);
         case StyleProp.BorderRounding:
-            return StrCast(doc?.[fieldKey + 'borderRounding'], StrCast(doc?.borderRounding, doc?._type_collection === CollectionViewType.Pile ? '50%' : ''));
+            return StrCast(doc?.[fieldKey + 'borderRounding'], StrCast(doc?.layout_borderRounding, doc?._type_collection === CollectionViewType.Pile ? '50%' : ''));
         case StyleProp.BorderPath:
             const borderPath = Doc.IsComicStyle(doc) &&
                 props?.renderDepth &&
@@ -235,38 +235,37 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
         }
         case StyleProp.BoxShadow: {
             if (!doc || opacity() === 0 || doc.noShadow) return undefined; // if it's not visible, then no shadow)
-            if (doc.boxShadow === 'standard') return Shadows.STANDARD_SHADOW;
+            if (doc.layout_boxShadow === 'standard') return Shadows.STANDARD_SHADOW;
             if (IsFollowLinkScript(doc?.onClick) && LinkManager.Links(doc).length && ![DocumentType.LINK, DocumentType.INK].includes(doc.type as any)) return StrCast(doc?._linkButtonShadow, 'lightblue 0em 0em 1em');
             switch (doc?.type) {
                 case DocumentType.COL:
                     return StrCast(
-                        doc?.boxShadow,
+                        doc?.layout_borderRounding,
                         doc?._type_collection === CollectionViewType.Pile
                             ? '4px 4px 10px 2px'
                             : lockedPosition() || doc?._isGroup || docProps?.LayoutTemplateString
                             ? undefined // groups have no drop shadow -- they're supposed to be "invisible".  LayoutString's imply collection is being rendered as something else (e.g., title of a Slide)
-                            : `${darkScheme() ? Colors.DARK_GRAY : Colors.MEDIUM_GRAY} ${StrCast(doc.boxShadow, '0.2vw 0.2vw 0.8vw')}`
+                            : `${darkScheme() ? Colors.DARK_GRAY : Colors.MEDIUM_GRAY} ${StrCast(doc.layout_borderRounding, '0.2vw 0.2vw 0.8vw')}`
                     );
 
                 case DocumentType.LABEL:
                     if (doc?.annotationOn !== undefined) return 'black 2px 2px 1px';
                 default:
                     return doc.z
-                        ? `#9c9396  ${StrCast(doc?.boxShadow, '10px 10px 0.9vw')}` // if it's a floating doc, give it a big shadow
+                        ? `#9c9396  ${StrCast(doc?.layout_boxShadow, '10px 10px 0.9vw')}` // if it's a floating doc, give it a big shadow
                         : props?.docViewPath().lastElement()?.rootDoc._freeform_useClusters
-                        ? `${backgroundCol()} ${StrCast(doc.boxShadow, `0vw 0vw ${(lockedPosition() ? 100 : 50) / (docProps?.NativeDimScaling?.() || 1)}px`)}` // if it's just in a cluster, make the shadown roughly match the cluster border extent
+                        ? `${backgroundCol()} ${StrCast(doc.layout_boxShadow, `0vw 0vw ${(lockedPosition() ? 100 : 50) / (docProps?.NativeDimScaling?.() || 1)}px`)}` // if it's just in a cluster, make the shadown roughly match the cluster border extent
                         : NumCast(doc.group, -1) !== -1
-                        ? `gray ${StrCast(doc.boxShadow, `0vw 0vw ${(lockedPosition() ? 100 : 50) / (docProps?.NativeDimScaling?.() || 1)}px`)}` // if it's just in a cluster, make the shadown roughly match the cluster border extent
+                        ? `gray ${StrCast(doc.layout_boxShadow, `0vw 0vw ${(lockedPosition() ? 100 : 50) / (docProps?.NativeDimScaling?.() || 1)}px`)}` // if it's just in a cluster, make the shadown roughly match the cluster border extent
                         : lockedPosition()
                         ? undefined // if it's a background & has a cluster color, make the shadow spread really big
-                        : StrCast(doc.boxShadow, '');
+                        : StrCast(doc.layout_boxShadow, '');
             }
         }
         case StyleProp.PointerEvents:
             const isInk = doc && StrCast(Doc.Layout(doc).layout).includes(InkingStroke.name) && !props?.LayoutTemplateString;
             if (docProps?.DocumentView?.().ComponentView?.overridePointerEvents?.() !== undefined) return docProps?.DocumentView?.().ComponentView?.overridePointerEvents?.();
             if (MainView.Instance._exploreMode || doc?.layout_unrendered) return isInk ? 'visiblePainted' : 'all';
-            if (doc?.pointerEvents) return StrCast(doc.pointerEvents);
             if (props?.contentPointerEvents) return StrCast(props.contentPointerEvents);
             if (props?.pointerEvents?.() === 'none') return 'none';
             if (opacity() === 0) return 'none';
@@ -284,9 +283,9 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
             };
             const filter = () => {
                 const showFilterIcon =
-                    StrListCast(doc?._docFilters).length || StrListCast(doc?._docRangeFilters).length
+                    StrListCast(doc?._childFilters).length || StrListCast(doc?._childFiltersByRanges).length
                         ? '#18c718bd' //'hasFilter'
-                        : docProps?.docFilters?.().filter(f => Utils.IsRecursiveFilter(f) && f !== Utils.noDragsDocFilter).length || docProps?.docRangeFilters().length
+                        : docProps?.childFilters?.().filter(f => Utils.IsRecursiveFilter(f) && f !== Utils.noDragsDocFilter).length || docProps?.childFiltersByRanges().length
                         ? 'orange' //'inheritsFilter'
                         : undefined;
                 return !showFilterIcon ? null : (
diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx
index 814a95ab8..62f47ba71 100644
--- a/src/client/views/TemplateMenu.tsx
+++ b/src/client/views/TemplateMenu.tsx
@@ -116,8 +116,8 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
                     styleProvider={DefaultStyleProvider}
                     setHeight={returnFalse}
                     docViewPath={returnEmptyDoclist}
-                    docFilters={returnEmptyFilter}
-                    docRangeFilters={returnEmptyFilter}
+                    childFilters={returnEmptyFilter}
+                    childFiltersByRanges={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
                     rootSelected={returnFalse}
                     onCheckedClick={this.scriptField}
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index dc430667b..fc3f713ce 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -130,8 +130,8 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> {
                     renderDepth={0}
                     focus={emptyFunction}
                     whenChildContentsActiveChanged={emptyFunction}
-                    docFilters={returnEmptyFilter}
-                    docRangeFilters={returnEmptyFilter}
+                    childFilters={returnEmptyFilter}
+                    childFiltersByRanges={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
                 />
             </div>
@@ -277,16 +277,16 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewMenu
     _saveFilterCommand = {
         params: ['target'],
         title: 'save filter',
-        script: `self.target._docFilters = compareLists(self['target-docFilters'],self.target._docFilters) ? undefined : copyField(self['target-docFilters']); 
+        script: `self.target._childFilters = compareLists(self['target-childFilters'],self.target._childFilters) ? undefined : copyField(self['target-childFilters']); 
                  self.target._searchFilterDocs = compareLists(self['target-searchFilterDocs'],self.target._searchFilterDocs) ? undefined: copyField(self['target-searchFilterDocs']);`,
         immediate: undoBatch((source: Doc[]) => {
-            this.target._docFilters = undefined;
+            this.target._childFilters = undefined;
             this.target._searchFilterDocs = undefined;
         }),
         initialize: (button: Doc) => {
             const activeDash = Doc.ActiveDashboard;
             if (activeDash) {
-                button['target-docFilters'] = (Doc.MySearcher._docFilters || activeDash._docFilters) instanceof ObjectField ? ObjectField.MakeCopy((Doc.MySearcher._docFilters || activeDash._docFilters) as any as ObjectField) : undefined;
+                button['target-childFilters'] = (Doc.MySearcher._childFilters || activeDash._childFilters) instanceof ObjectField ? ObjectField.MakeCopy((Doc.MySearcher._childFilters || activeDash._childFilters) as any as ObjectField) : undefined;
                 button['target-searchFilterDocs'] = activeDash._searchFilterDocs instanceof ObjectField ? ObjectField.MakeCopy(activeDash._searchFilterDocs as any as ObjectField) : undefined;
             }
         },
diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx
index fc265e2b9..675f23970 100644
--- a/src/client/views/collections/CollectionNoteTakingView.tsx
+++ b/src/client/views/collections/CollectionNoteTakingView.tsx
@@ -201,13 +201,17 @@ export class CollectionNoteTakingView extends CollectionSubView() {
     };
 
     styleProvider = (doc: Doc | undefined, props: Opt<DocumentViewProps>, property: string) => {
-        if (property === StyleProp.BoxShadow && doc && DragManager.docsBeingDragged.includes(doc)) {
-            return `#9c9396  ${StrCast(doc?.boxShadow, '10px 10px 0.9vw')}`;
-        }
-        if (property === StyleProp.Opacity && doc) {
-            if (this.props.childOpacity) {
-                return this.props.childOpacity();
-            }
+        switch (property) {
+            case StyleProp.BoxShadow:
+                if (doc && DragManager.docsBeingDragged.includes(doc)) {
+                    return `#9c9396 ${StrCast(doc?.layout_boxShadow, '10px 10px 0.9vw')}`;
+                }
+                break;
+            case StyleProp.Opacity:
+                if (doc && this.props.childOpacity) {
+                    return this.props.childOpacity();
+                }
+                break;
         }
         return this.props.styleProvider?.(doc, props, property);
     };
@@ -251,11 +255,11 @@ export class CollectionNoteTakingView extends CollectionSubView() {
                 onDoubleClick={this.onChildDoubleClickHandler}
                 ScreenToLocalTransform={noteTakingDocTransform}
                 focus={this.focusDocument}
-                docFilters={this.childDocFilters}
+                childFilters={this.childDocFilters}
                 hideDecorationTitle={this.props.childHideDecorationTitle?.()}
                 hideResizeHandles={this.props.childHideResizeHandles?.()}
                 hideTitle={this.props.childHideTitle?.()}
-                docRangeFilters={this.childDocRangeFilters}
+                childFiltersByRanges={this.childDocRangeFilters}
                 searchFilterDocs={this.searchFilterDocs}
                 addDocument={this.props.addDocument}
                 moveDocument={this.props.moveDocument}
@@ -603,42 +607,6 @@ export class CollectionNoteTakingView extends CollectionSubView() {
         return eles;
     }
 
-    @computed get buttonMenu() {
-        const menuDoc: Doc = Cast(this.rootDoc.buttonMenuDoc, Doc, null);
-        if (menuDoc) {
-            const width = NumCast(menuDoc._width, 30);
-            const height = NumCast(menuDoc._height, 30);
-            return (
-                <div className="buttonMenu-docBtn" style={{ width, height }}>
-                    <DocumentView
-                        Document={menuDoc}
-                        DataDoc={menuDoc}
-                        isContentActive={this.props.isContentActive}
-                        isDocumentActive={returnTrue}
-                        addDocument={this.props.addDocument}
-                        moveDocument={this.props.moveDocument}
-                        addDocTab={this.props.addDocTab}
-                        pinToPres={emptyFunction}
-                        rootSelected={this.props.isSelected}
-                        removeDocument={this.props.removeDocument}
-                        ScreenToLocalTransform={Transform.Identity}
-                        PanelWidth={() => 35}
-                        PanelHeight={() => 35}
-                        renderDepth={this.props.renderDepth}
-                        focus={emptyFunction}
-                        styleProvider={this.props.styleProvider}
-                        docViewPath={returnEmptyDoclist}
-                        whenChildContentsActiveChanged={emptyFunction}
-                        bringToFront={emptyFunction}
-                        docFilters={this.props.docFilters}
-                        docRangeFilters={this.props.docRangeFilters}
-                        searchFilterDocs={this.props.searchFilterDocs}
-                    />
-                </div>
-            );
-        }
-    }
-
     @computed get nativeWidth() {
         return Doc.NativeWidth(this.layoutDoc);
     }
@@ -658,35 +626,25 @@ export class CollectionNoteTakingView extends CollectionSubView() {
 
     render() {
         TraceMobx();
-        const buttonMenu = this.rootDoc.buttonMenu;
-        const noviceExplainer = StrCast(this.rootDoc.explainer);
         return (
-            <>
-                {buttonMenu || noviceExplainer ? (
-                    <div className="documentButtonMenu" key="buttons">
-                        {buttonMenu ? this.buttonMenu : null}
-                        {Doc.UserDoc().noviceMode && noviceExplainer ? <div className="documentExplanation">{noviceExplainer}</div> : null}
-                    </div>
-                ) : null}
-                <div
-                    className="collectionNoteTakingView"
-                    ref={this.createRef}
-                    key="notes"
-                    style={{
-                        overflowY: this.props.isContentActive() ? 'auto' : 'hidden',
-                        background: this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor),
-                        pointerEvents: this.backgroundEvents ? 'all' : undefined,
-                    }}
-                    onScroll={action(e => (this._scroll = e.currentTarget.scrollTop))}
-                    onPointerLeave={action(e => (this.docsDraggedRowCol.length = 0))}
-                    onPointerMove={e => e.buttons && this.onPointerMove(false, e.clientX, e.clientY)}
-                    onDragOver={e => this.onPointerMove(true, e.clientX, e.clientY)}
-                    onDrop={this.onExternalDrop.bind(this)}
-                    onContextMenu={this.onContextMenu}
-                    onWheel={e => this.props.isContentActive(true) && e.stopPropagation()}>
-                    {this.renderedSections}
-                </div>
-            </>
+            <div
+                className="collectionNoteTakingView"
+                ref={this.createRef}
+                key="notes"
+                style={{
+                    overflowY: this.props.isContentActive() ? 'auto' : 'hidden',
+                    background: this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor),
+                    pointerEvents: this.backgroundEvents ? 'all' : undefined,
+                }}
+                onScroll={action(e => (this._scroll = e.currentTarget.scrollTop))}
+                onPointerLeave={action(e => (this.docsDraggedRowCol.length = 0))}
+                onPointerMove={e => e.buttons && this.onPointerMove(false, e.clientX, e.clientY)}
+                onDragOver={e => this.onPointerMove(true, e.clientX, e.clientY)}
+                onDrop={this.onExternalDrop.bind(this)}
+                onContextMenu={this.onContextMenu}
+                onWheel={e => this.props.isContentActive(true) && e.stopPropagation()}>
+                {this.renderedSections}
+            </div>
         );
     }
 }
diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx
index bbc91aa6e..57d9bbb49 100644
--- a/src/client/views/collections/CollectionPileView.tsx
+++ b/src/client/views/collections/CollectionPileView.tsx
@@ -23,7 +23,7 @@ export class CollectionPileView extends CollectionSubView() {
 
     componentDidMount() {
         if (this.layoutEngine() !== computePassLayout.name && this.layoutEngine() !== computeStarburstLayout.name) {
-            this.Document._pileLayoutEngine = computePassLayout.name;
+            this.Document._freeform_pileEngine = computePassLayout.name;
         }
         this._originalChrome = this.layoutDoc._chromeHidden;
         this.layoutDoc._chromeHidden = true;
@@ -33,7 +33,7 @@ export class CollectionPileView extends CollectionSubView() {
         Object.values(this._disposers).forEach(disposer => disposer?.());
     }
 
-    layoutEngine = () => StrCast(this.Document._pileLayoutEngine);
+    layoutEngine = () => StrCast(this.Document._freeform_pileEngine);
 
     @undoBatch
     addPileDoc = (doc: Doc | Doc[]) => {
@@ -73,28 +73,29 @@ export class CollectionPileView extends CollectionSubView() {
 
     // toggles the pileup between starburst to compact
     toggleStarburst = action(() => {
+        this.layoutDoc._freeform_scale = undefined;
         if (this.layoutEngine() === computeStarburstLayout.name) {
             if (this.rootDoc[Width]() !== NumCast(this.rootDoc._starburstDiameter, 500)) {
                 this.rootDoc._starburstDiameter = this.rootDoc[Width]();
             }
             const defaultSize = 110;
-            this.rootDoc.x = NumCast(this.rootDoc.x) + this.layoutDoc[Width]() / 2 - NumCast(this.layoutDoc._starburstPileWidth, defaultSize) / 2;
-            this.rootDoc.y = NumCast(this.rootDoc.y) + this.layoutDoc[Height]() / 2 - NumCast(this.layoutDoc._starburstPileHeight, defaultSize) / 2;
-            this.layoutDoc._width = NumCast(this.layoutDoc._starburstPileWidth, defaultSize);
-            this.layoutDoc._height = NumCast(this.layoutDoc._starburstPileHeight, defaultSize);
+            this.rootDoc.x = NumCast(this.rootDoc.x) + this.layoutDoc[Width]() / 2 - NumCast(this.layoutDoc._freeform_pileWidth, defaultSize) / 2;
+            this.rootDoc.y = NumCast(this.rootDoc.y) + this.layoutDoc[Height]() / 2 - NumCast(this.layoutDoc._freeform_pileHeight, defaultSize) / 2;
+            this.layoutDoc._width = NumCast(this.layoutDoc._freeform_pileWidth, defaultSize);
+            this.layoutDoc._height = NumCast(this.layoutDoc._freeform_pileHeight, defaultSize);
             DocUtils.pileup(this.childDocs, undefined, undefined, NumCast(this.layoutDoc._width) / 2, false);
             this.layoutDoc._freeform_panX = 0;
             this.layoutDoc._freeform_panY = -10;
-            this.props.Document._pileLayoutEngine = computePassLayout.name;
+            this.props.Document._freeform_pileEngine = computePassLayout.name;
         } else {
             const defaultSize = NumCast(this.rootDoc._starburstDiameter, 500);
             this.rootDoc.x = NumCast(this.rootDoc.x) + this.layoutDoc[Width]() / 2 - defaultSize / 2;
             this.rootDoc.y = NumCast(this.rootDoc.y) + this.layoutDoc[Height]() / 2 - defaultSize / 2;
-            this.layoutDoc._starburstPileWidth = this.layoutDoc[Width]();
-            this.layoutDoc._starburstPileHeight = this.layoutDoc[Height]();
+            this.layoutDoc._freeform_pileWidth = this.layoutDoc[Width]();
+            this.layoutDoc._freeform_pileHeight = this.layoutDoc[Height]();
             this.layoutDoc._freeform_panX = this.layoutDoc._freeform_panY = 0;
             this.layoutDoc._width = this.layoutDoc._height = defaultSize;
-            this.props.Document._pileLayoutEngine = computeStarburstLayout.name;
+            this.props.Document._freeform_pileEngine = computeStarburstLayout.name;
         }
     });
 
diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index b131d38d8..9d5cb257a 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -404,15 +404,15 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
             docAnchor ??
             Docs.Create.LabelDocument({
                 title: ComputedField.MakeFunction(`self["${endTag}"] ? "#" + formatToTime(self["${startTag}"]) + "-" + formatToTime(self["${endTag}"]) : "#" + formatToTime(self["${startTag}"])`) as any,
-                _minFontSize: 12,
-                _maxFontSize: 24,
+                _label_minFontSize: 12,
+                _label_maxFontSize: 24,
                 _stayInCollection: true,
                 backgroundColor: 'rgba(128, 128, 128, 0.5)',
                 layout_hideLinkButton: true,
                 onClick: FollowLinkScript(),
                 annotationOn: rootDoc,
-                _timelineLabel: true,
-                borderRounding: anchorEndTime === undefined ? '100%' : undefined,
+                _isTimelineLabel: true,
+                layout_borderRounding: anchorEndTime === undefined ? '100%' : undefined,
             });
         Doc.GetProto(anchor)[startTag] = anchorStartTime;
         Doc.GetProto(anchor)[endTag] = anchorEndTime;
@@ -752,7 +752,7 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps>
             if (timelineOnly) {
                 if (!left && time !== undefined && time <= NumCast(anchor[this.props.startTag])) time = undefined;
                 Doc.SetInPlace(anchor, left ? this.props.startTag : this.props.endTag, time, true);
-                if (!left) Doc.SetInPlace(anchor, 'borderRounding', time !== undefined ? undefined : '100%', true);
+                if (!left) Doc.SetInPlace(anchor, 'layout_borderRounding', time !== undefined ? undefined : '100%', true);
             } else {
                 anchor[left ? '_timecodeToShow' : '_timecodeToHide'] = time;
             }
@@ -820,8 +820,8 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps>
                     focus={focusFunc}
                     isContentActive={returnFalse}
                     searchFilterDocs={returnEmptyDoclist}
-                    docFilters={returnEmptyFilter}
-                    docRangeFilters={returnEmptyFilter}
+                    childFilters={returnEmptyFilter}
+                    childFiltersByRanges={returnEmptyFilter}
                     rootSelected={returnFalse}
                     onClick={script}
                     onDoubleClick={this.props.layoutDoc.autoPlayAnchors ? undefined : doublescript}
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 56f53afe6..3c0d8cbc3 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -346,11 +346,11 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
                 onDoubleClick={this.onChildDoubleClickHandler}
                 ScreenToLocalTransform={stackedDocTransform}
                 focus={this.focusDocument}
-                docFilters={this.childDocFilters}
+                childFilters={this.childDocFilters}
                 hideDecorationTitle={this.props.childHideDecorationTitle?.()}
                 hideResizeHandles={this.props.childHideResizeHandles?.()}
                 hideTitle={this.props.childHideTitle?.()}
-                docRangeFilters={this.childDocRangeFilters}
+                childFiltersByRanges={this.childDocRangeFilters}
                 searchFilterDocs={this.searchFilterDocs}
                 xPadding={NumCast(this.layoutDoc._childXPadding, this.props.childXPadding)}
                 yPadding={NumCast(this.layoutDoc._childYPadding, this.props.childYPadding)}
@@ -650,7 +650,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
 
     return35 = () => 35;
     @computed get buttonMenu() {
-        const menuDoc: Doc = Cast(this.rootDoc.buttonMenuDoc, Doc, null);
+        const menuDoc: Doc = Cast(this.rootDoc.layout_headerButton, Doc, null);
         // TODO:glr Allow support for multiple buttons
         if (menuDoc) {
             const width: number = NumCast(menuDoc._width, 30);
@@ -679,8 +679,8 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
                         docViewPath={returnEmptyDoclist}
                         whenChildContentsActiveChanged={emptyFunction}
                         bringToFront={emptyFunction}
-                        docFilters={this.props.docFilters}
-                        docRangeFilters={this.props.docRangeFilters}
+                        childFilters={this.props.childFilters}
+                        childFiltersByRanges={this.props.childFiltersByRanges}
                         searchFilterDocs={this.props.searchFilterDocs}
                     />
                 </div>
@@ -711,7 +711,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
             contents: '+ ADD A GROUP',
         };
         const buttonMenu = this.rootDoc.buttonMenu;
-        const noviceExplainer = this.rootDoc.explainer;
+        const noviceExplainer = this.rootDoc.layout_explainer;
         return (
             <>
                 {buttonMenu || noviceExplainer ? (
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 967d1d40e..d1b7f6ff6 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -28,8 +28,8 @@ export function CollectionSubView<X>(moreProps?: X) {
         private gestureDisposer?: GestureUtils.GestureEventDisposer;
         protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
         protected _mainCont?: HTMLDivElement;
-        @observable _focusFilters: Opt<string[]>; // docFilters that are overridden when previewing a link to an anchor which has docFilters set on it
-        @observable _focusRangeFilters: Opt<string[]>; // docRangeFilters that are overridden when previewing a link to an anchor which has docRangeFilters set on it
+        @observable _focusFilters: Opt<string[]>; // childFilters that are overridden when previewing a link to an anchor which has childFilters set on it
+        @observable _focusRangeFilters: Opt<string[]>; // childFiltersByRanges that are overridden when previewing a link to an anchor which has childFiltersByRanges set on it
         protected createDashEventsTarget = (ele: HTMLDivElement | null) => {
             //used for stacking and masonry view
             this.dropDisposer?.();
@@ -81,13 +81,13 @@ export function CollectionSubView<X>(moreProps?: X) {
         get childDocList() {
             return Cast(this.dataField, listSpec(Doc));
         }
-        collectionFilters = () => this._focusFilters ?? StrListCast(this.props.Document._docFilters);
-        collectionRangeDocFilters = () => this._focusRangeFilters ?? Cast(this.props.Document._docRangeFilters, listSpec('string'), []);
+        collectionFilters = () => this._focusFilters ?? StrListCast(this.props.Document._childFilters);
+        collectionRangeDocFilters = () => this._focusRangeFilters ?? Cast(this.props.Document._childFiltersByRanges, listSpec('string'), []);
         // child filters apply to the descendants of the documents in this collection
-        childDocFilters = () => [...(this.props.docFilters?.().filter(f => Utils.IsRecursiveFilter(f)) || []), ...this.collectionFilters()];
+        childDocFilters = () => [...(this.props.childFilters?.().filter(f => Utils.IsRecursiveFilter(f)) || []), ...this.collectionFilters()];
         // unrecursive filters apply to the documents in the collection, but no their children.  See Utils.noRecursionHack
-        unrecursiveDocFilters = () => [...(this.props.docFilters?.().filter(f => !Utils.IsRecursiveFilter(f)) || [])];
-        childDocRangeFilters = () => [...(this.props.docRangeFilters?.() || []), ...this.collectionRangeDocFilters()];
+        unrecursiveDocFilters = () => [...(this.props.childFilters?.().filter(f => !Utils.IsRecursiveFilter(f)) || [])];
+        childDocRangeFilters = () => [...(this.props.childFiltersByRanges?.() || []), ...this.collectionRangeDocFilters()];
         searchFilterDocs = () => this.props.searchFilterDocs?.() ?? DocListCast(this.props.Document._searchFilterDocs);
         @computed.struct get childDocs() {
             TraceMobx();
@@ -109,20 +109,20 @@ export function CollectionSubView<X>(moreProps?: X) {
             const childDocs = rawdocs.filter(d => !(d instanceof Promise) && GetEffectiveAcl(Doc.GetProto(d)) !== AclPrivate && (this.props.ignoreUnrendered || !d.layout_unrendered)).map(d => d as Doc);
 
             const childDocFilters = this.childDocFilters();
-            const docRangeFilters = this.childDocRangeFilters();
+            const childFiltersByRanges = this.childDocRangeFilters();
             const searchDocs = this.searchFilterDocs();
-            if (this.props.Document.dontRegisterView || (!childDocFilters.length && !this.unrecursiveDocFilters().length && !docRangeFilters.length && !searchDocs.length)) {
+            if (this.props.Document.dontRegisterView || (!childDocFilters.length && !this.unrecursiveDocFilters().length && !childFiltersByRanges.length && !searchDocs.length)) {
                 return childDocs.filter(cd => !cd.cookies); // remove any documents that require a cookie if there are no filters to provide one
             }
 
             const docsforFilter: Doc[] = [];
             childDocs.forEach(d => {
                 // dragging facets
-                const dragged = this.props.docFilters?.().some(f => f.includes(Utils.noDragsDocFilter));
+                const dragged = this.props.childFilters?.().some(f => f.includes(Utils.noDragsDocFilter));
                 if (dragged && DragManager.docsBeingDragged.includes(d)) return false;
-                let notFiltered = d.z || Doc.IsSystem(d) || DocUtils.FilterDocs([d], this.unrecursiveDocFilters(), docRangeFilters, this.props.Document).length > 0;
+                let notFiltered = d.z || Doc.IsSystem(d) || DocUtils.FilterDocs([d], this.unrecursiveDocFilters(), childFiltersByRanges, this.props.Document).length > 0;
                 if (notFiltered) {
-                    notFiltered = (!searchDocs.length || searchDocs.includes(d)) && DocUtils.FilterDocs([d], childDocFilters, docRangeFilters, this.props.Document).length > 0;
+                    notFiltered = (!searchDocs.length || searchDocs.includes(d)) && DocUtils.FilterDocs([d], childDocFilters, childFiltersByRanges, this.props.Document).length > 0;
                     const fieldKey = Doc.LayoutFieldKey(d);
                     const annos = !Field.toString(Doc.LayoutField(d) as Field).includes(CollectionView.name);
                     const data = d[annos ? fieldKey + '_annotations' : fieldKey];
@@ -131,13 +131,14 @@ export function CollectionSubView<X>(moreProps?: X) {
                         let subDocs = [...DocListCast(data), ...DocListCast(side)];
                         if (subDocs.length > 0) {
                             let newarray: Doc[] = [];
-                            notFiltered = notFiltered || (!searchDocs.length && DocUtils.FilterDocs(subDocs, childDocFilters, docRangeFilters, d).length);
+                            notFiltered = notFiltered || (!searchDocs.length && DocUtils.FilterDocs(subDocs, childDocFilters, childFiltersByRanges, d).length);
                             while (subDocs.length > 0 && !notFiltered) {
                                 newarray = [];
                                 subDocs.forEach(t => {
                                     const fieldKey = Doc.LayoutFieldKey(t);
                                     const annos = !Field.toString(Doc.LayoutField(t) as Field).includes(CollectionView.name);
-                                    notFiltered = notFiltered || ((!searchDocs.length || searchDocs.includes(t)) && ((!childDocFilters.length && !docRangeFilters.length) || DocUtils.FilterDocs([t], childDocFilters, docRangeFilters, d).length));
+                                    notFiltered =
+                                        notFiltered || ((!searchDocs.length || searchDocs.includes(t)) && ((!childDocFilters.length && !childFiltersByRanges.length) || DocUtils.FilterDocs([t], childDocFilters, childFiltersByRanges, d).length));
                                     DocListCast(t[annos ? fieldKey + '_annotations' : fieldKey]).forEach(newdoc => newarray.push(newdoc));
                                     annos && DocListCast(t[fieldKey + '_sidebar']).forEach(newdoc => newarray.push(newdoc));
                                 });
diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx
index 49a90d828..60e6815e5 100644
--- a/src/client/views/collections/CollectionTimeView.tsx
+++ b/src/client/views/collections/CollectionTimeView.tsx
@@ -125,8 +125,8 @@ export class CollectionTimeView extends CollectionSubView() {
 
     goTo = (prevFilterIndex: number) => {
         this.layoutDoc._pivotField = this.layoutDoc['_prevPivotFields' + prevFilterIndex];
-        this.layoutDoc._docFilters = ObjectField.MakeCopy(this.layoutDoc['_prevDocFilter' + prevFilterIndex] as ObjectField);
-        this.layoutDoc._docRangeFilters = ObjectField.MakeCopy(this.layoutDoc['_prevDocRangeFilters' + prevFilterIndex] as ObjectField);
+        this.layoutDoc._childFilters = ObjectField.MakeCopy(this.layoutDoc['_prevDocFilter' + prevFilterIndex] as ObjectField);
+        this.layoutDoc._childFiltersByRanges = ObjectField.MakeCopy(this.layoutDoc['_prevDocRangeFilters' + prevFilterIndex] as ObjectField);
         this.layoutDoc._prevFilterIndex = prevFilterIndex;
     };
 
@@ -136,7 +136,7 @@ export class CollectionTimeView extends CollectionSubView() {
         if (prevFilterIndex > 0) {
             this.goTo(prevFilterIndex - 1);
         } else {
-            this.layoutDoc._docFilters = new List([]);
+            this.layoutDoc._childFilters = new List([]);
         }
     };
 
@@ -145,7 +145,7 @@ export class CollectionTimeView extends CollectionSubView() {
             <div className="collectionTimeView-innards" key="timeline" style={{ pointerEvents: this.props.isContentActive() ? undefined : 'none' }} onClick={this.contentsDown}>
                 <CollectionFreeFormView
                     {...this.props}
-                    engineProps={{ pivotField: this.pivotField, docFilters: this.childDocFilters, docRangeFilters: this.childDocRangeFilters }}
+                    engineProps={{ pivotField: this.pivotField, childFilters: this.childDocFilters, childFiltersByRanges: this.childDocRangeFilters }}
                     fitContentsToBox={returnTrue}
                     childClickScript={this._childClickedScript}
                     viewDefDivClick={this.layoutEngine() === computeTimelineLayout.name ? undefined : this._viewDefDivClick}
@@ -276,12 +276,12 @@ export class CollectionTimeView extends CollectionSubView() {
 ScriptingGlobals.add(function pivotColumnClick(pivotDoc: Doc, bounds: ViewDefBounds) {
     const pivotField = StrCast(pivotDoc._pivotField, 'author');
     let prevFilterIndex = NumCast(pivotDoc._prevFilterIndex);
-    const originalFilter = StrListCast(ObjectField.MakeCopy(pivotDoc._docFilters as ObjectField));
-    pivotDoc['_prevDocFilter' + prevFilterIndex] = ObjectField.MakeCopy(pivotDoc._docFilters as ObjectField);
-    pivotDoc['_prevDocRangeFilters' + prevFilterIndex] = ObjectField.MakeCopy(pivotDoc._docRangeFilters as ObjectField);
+    const originalFilter = StrListCast(ObjectField.MakeCopy(pivotDoc._childFilters as ObjectField));
+    pivotDoc['_prevDocFilter' + prevFilterIndex] = ObjectField.MakeCopy(pivotDoc._childFilters as ObjectField);
+    pivotDoc['_prevDocRangeFilters' + prevFilterIndex] = ObjectField.MakeCopy(pivotDoc._childFiltersByRanges as ObjectField);
     pivotDoc['_prevPivotFields' + prevFilterIndex] = pivotField;
     pivotDoc._prevFilterIndex = ++prevFilterIndex;
-    pivotDoc._docFilters = new List();
+    pivotDoc._childFilters = new List();
     setTimeout(
         action(() => {
             const filterVals = bounds.payload as string[];
@@ -292,7 +292,7 @@ ScriptingGlobals.add(function pivotColumnClick(pivotDoc: Doc, bounds: ViewDefBou
                     pivotDoc._pivotField = filterVals[0];
                 }
             }
-            const newFilters = StrListCast(pivotDoc._docFilters);
+            const newFilters = StrListCast(pivotDoc._childFilters);
             if (newFilters.length && originalFilter.length && newFilters.lastElement() === originalFilter.lastElement()) {
                 pivotDoc._prevFilterIndex = --prevFilterIndex;
                 pivotDoc['_prevDocFilter' + prevFilterIndex] = undefined;
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 969658238..ed1e0c067 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -240,8 +240,8 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
                 PanelHeight={this.documentTitleHeight}
                 NativeDimScaling={returnOne}
                 onKey={this.onKey}
-                docFilters={returnEmptyFilter}
-                docRangeFilters={returnEmptyFilter}
+                childFilters={returnEmptyFilter}
+                childFiltersByRanges={returnEmptyFilter}
                 searchFilterDocs={returnEmptyDoclist}
                 addDocument={returnFalse}
                 moveDocument={returnFalse}
@@ -314,12 +314,12 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
     }
 
     @computed get noviceExplainer() {
-        return !Doc.noviceMode || !this.rootDoc.explainer ? null : <div className="documentExplanation"> {StrCast(this.rootDoc.explainer)} </div>;
+        return !Doc.noviceMode || !this.rootDoc.layout_explainer ? null : <div className="documentExplanation"> {StrCast(this.rootDoc.layout_explainer)} </div>;
     }
 
     return35 = () => 35;
     @computed get buttonMenu() {
-        const menuDoc = Cast(this.rootDoc.buttonMenuDoc, Doc, null);
+        const menuDoc = Cast(this.rootDoc.layout_headerButton, Doc, null);
         // To create a multibutton menu add a CollectionLinearView
         return !menuDoc ? null : (
             <div className="buttonMenu-docBtn" style={{ width: NumCast(menuDoc._width, 30), height: NumCast(menuDoc._height, 30) }}>
@@ -343,8 +343,8 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
                     docViewPath={returnEmptyDoclist}
                     whenChildContentsActiveChanged={emptyFunction}
                     bringToFront={emptyFunction}
-                    docFilters={this.props.docFilters}
-                    docRangeFilters={this.props.docRangeFilters}
+                    childFilters={this.props.childFilters}
+                    childFiltersByRanges={this.props.childFiltersByRanges}
                     searchFilterDocs={this.props.searchFilterDocs}
                 />
             </div>
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 710e33b1c..75e4e8abf 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -432,8 +432,8 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                     PanelWidth={this.PanelWidth}
                     PanelHeight={this.PanelHeight}
                     styleProvider={DefaultStyleProvider}
-                    docFilters={CollectionDockingView.Instance?.childDocFilters ?? returnEmptyDoclist}
-                    docRangeFilters={CollectionDockingView.Instance?.childDocRangeFilters ?? returnEmptyDoclist}
+                    childFilters={CollectionDockingView.Instance?.childDocFilters ?? returnEmptyDoclist}
+                    childFiltersByRanges={CollectionDockingView.Instance?.childDocRangeFilters ?? returnEmptyDoclist}
                     searchFilterDocs={CollectionDockingView.Instance?.searchFilterDocs ?? returnEmptyDoclist}
                     addDocument={undefined}
                     removeDocument={this.remDocTab}
@@ -602,8 +602,8 @@ export class TabMinimapView extends React.Component<TabMinimapViewProps> {
                     styleProvider={TabMinimapView.miniStyleProvider}
                     addDocTab={this.props.addDocTab}
                     pinToPres={TabDocView.PinDoc}
-                    docFilters={CollectionDockingView.Instance?.childDocFilters ?? returnEmptyDoclist}
-                    docRangeFilters={CollectionDockingView.Instance?.childDocRangeFilters ?? returnEmptyDoclist}
+                    childFilters={CollectionDockingView.Instance?.childDocFilters ?? returnEmptyDoclist}
+                    childFiltersByRanges={CollectionDockingView.Instance?.childDocRangeFilters ?? returnEmptyDoclist}
                     searchFilterDocs={CollectionDockingView.Instance?.searchFilterDocs ?? returnEmptyDoclist}
                     fitContentsToBox={returnTrue}
                 />
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index ca9471f6f..9039875c1 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -119,7 +119,7 @@ export class TreeView extends React.Component<TreeViewProps> {
         return 'TreeView(' + this.props.document.title + ')';
     } // this makes mobx trace() statements more descriptive
     get defaultExpandedView() {
-        return this.doc.type_collection === CollectionViewType.Docking
+        return this.doc._type_collection === CollectionViewType.Docking
             ? this.fieldKey
             : this.props.treeView.dashboardMode
             ? this.fieldKey
@@ -388,7 +388,7 @@ export class TreeView extends React.Component<TreeViewProps> {
         };
         const addDoc = inside ? localAdd : parentAddDoc;
         const move = (!dropAction || dropAction === 'proto' || dropAction === 'move' || dropAction === 'same') && moveDocument;
-        const canAdd = (!this.props.treeView.outlineMode && !StrCast((inside ? this.props.document : this.props.treeViewParent)?.freezeChildren).includes('add')) || forceAdd;
+        const canAdd = (!this.props.treeView.outlineMode && !StrCast((inside ? this.props.document : this.props.treeViewParent)?.treeViewFreezeChildren).includes('add')) || forceAdd;
         if (canAdd) {
             this.props.parentTreeView instanceof TreeView && (this.props.parentTreeView.dropping = true);
             const res = UndoManager.RunInTempBatch(() => droppedDocuments.reduce((added, d) => (move ? move(d, undefined, addDoc) || (dropAction === 'proto' ? addDoc(d) : false) : addDoc(d)) || added, false));
@@ -714,7 +714,7 @@ export class TreeView extends React.Component<TreeViewProps> {
         const data = () => (this.childDocs || this.props.treeView.dashboardMode ? this.fieldKey : '');
         const embeddings = () => (this.props.treeView.dashboardMode ? '' : 'embeddings');
         const fields = () => (Doc.noviceMode ? '' : 'fields');
-        const layout = Doc.noviceMode || this.doc.type_collection === CollectionViewType.Docking ? [] : ['layout'];
+        const layout = Doc.noviceMode || this.doc._type_collection === CollectionViewType.Docking ? [] : ['layout'];
         return [data(), ...layout, ...(this.props.treeView.fileSysMode ? [embeddings(), links(), annos()] : []), fields()].filter(m => m);
     }
     @action
@@ -732,7 +732,7 @@ export class TreeView extends React.Component<TreeViewProps> {
         return this.props.treeViewHideHeaderFields() || this.doc.treeViewHideHeaderFields ? null : (
             <>
                 {customHeaderButtons} {/* e.g.,. hide button is set by dashboardStyleProvider */}
-                {this.doc.hideContextMenu ? null : (
+                {this.doc._layout_hideContextMenu ? null : (
                     <FontAwesomeIcon
                         title="context menu"
                         key="bars"
@@ -772,7 +772,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                 ? []
                 : this.props.treeView.fileSysMode && this.doc === Doc.GetProto(this.doc)
                 ? [openEmbedding, makeFolder]
-                : this.doc.type_collection === CollectionViewType.Docking
+                : this.doc._type_collection === CollectionViewType.Docking
                 ? []
                 : [deleteItem, openEmbedding, focusDoc]),
         ];
@@ -930,13 +930,13 @@ export class TreeView extends React.Component<TreeViewProps> {
                 focus={this.refocus}
                 whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
                 bringToFront={emptyFunction}
-                disableDocBrushing={this.props.treeView.props.disableDocBrushing}
+                disableBrushing={this.props.treeView.props.disableBrushing}
                 hideLinkButton={BoolCast(this.props.treeView.props.Document.childHideLinkButton)}
                 dontRegisterView={BoolCast(this.props.treeView.props.Document.childDontRegisterViews, this.props.dontRegisterView)}
                 xPadding={NumCast(this.props.treeView.props.Document.childXPadding, this.props.treeView.props.childXPadding)}
                 yPadding={NumCast(this.props.treeView.props.Document.childYPadding, this.props.treeView.props.childYPadding)}
-                docFilters={returnEmptyFilter}
-                docRangeFilters={returnEmptyFilter}
+                childFilters={returnEmptyFilter}
+                childFiltersByRanges={returnEmptyFilter}
                 searchFilterDocs={returnEmptyDoclist}
             />
         );
@@ -1010,8 +1010,8 @@ export class TreeView extends React.Component<TreeViewProps> {
                     treeViewDoc={this.props.treeView?.props.Document}
                     rootSelected={returnTrue}
                     docViewPath={this.props.treeView.props.docViewPath}
-                    docFilters={returnEmptyFilter}
-                    docRangeFilters={returnEmptyFilter}
+                    childFilters={returnEmptyFilter}
+                    childFiltersByRanges={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
                     addDocument={this.props.addDocument}
                     moveDocument={this.move}
@@ -1021,7 +1021,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                     yPadding={NumCast(this.props.treeView.props.Document.childYPadding, this.props.treeView.props.childYPadding)}
                     addDocTab={this.props.addDocTab}
                     pinToPres={this.props.treeView.props.pinToPres}
-                    disableDocBrushing={this.props.treeView.props.disableDocBrushing}
+                    disableBrushing={this.props.treeView.props.disableBrushing}
                     bringToFront={returnFalse}
                     scriptContext={this}
                 />
@@ -1211,7 +1211,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                         onCheckedClick={onCheckedClick}
                         onChildClick={onChildClick}
                         renderDepth={renderDepth}
-                        removeDoc={StrCast(treeViewParent.freezeChildren).includes('remove') ? undefined : remove}
+                        removeDoc={StrCast(treeViewParent.treeViewFreezeChildren).includes('remove') ? undefined : remove}
                         addDocument={addDocument}
                         styleProvider={styleProvider}
                         panelWidth={rowWidth}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
index 6202dcacc..f1d98d22a 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
@@ -59,7 +59,7 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
             0
         ); // since the render code depends on querying the Dom through getBoudndingClientRect, we need to delay triggering render()
         setTimeout(
-            action(() => (!LinkDocs.length || !linkDoc.layout_linkDisplay) && (this._opacity = 0.05)),
+            action(() => (!LinkDocs.length || !linkDoc.link_displayLine) && (this._opacity = 0.05)),
             750
         ); // this will unhighlight the link line.
         const a = A.ContentDiv.getBoundingClientRect();
@@ -77,7 +77,7 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
         const targetBhyperlink = Array.from(window.document.getElementsByClassName((linkDoc.link_anchor_2 as Doc)[Id])).lastElement();
         if ((!targetAhyperlink && !a.width) || (!targetBhyperlink && !b.width)) return;
         if (!targetAhyperlink) {
-            if (linkDoc.layout_autoMoveAnchors) {
+            if (linkDoc.link_autoMoveAnchors) {
                 linkDoc.link_anchor_1_x = ((apt.point.x - aleft) / awidth) * 100;
                 linkDoc.link_anchor_1_y = ((apt.point.y - atop) / aheight) * 100;
             }
@@ -92,7 +92,7 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
             else linkDoc.opacity = 1;
         }
         if (!targetBhyperlink) {
-            if (linkDoc.layout_autoMoveAnchors) {
+            if (linkDoc.link_autoMoveAnchors) {
                 linkDoc.link_anchor_2_x = ((bpt.point.x - bleft) / bwidth) * 100;
                 linkDoc.link_anchor_2_y = ((bpt.point.y - btop) / bheight) * 100;
             }
@@ -247,7 +247,7 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
         const { a, b, pt1norm, pt2norm, aActive, bActive, textX, textY, pt1, pt2 } = this.renderData;
         const linkRelationship = Field.toString(link?.link_relationship as any as Field); //get string representing relationship
         const linkRelationshipList = Doc.UserDoc().link_relationshipList as List<string>;
-        const linkColorList = Doc.UserDoc().linkColorList as List<string>;
+        const linkColorList = Doc.UserDoc().link_ColorList as List<string>;
         const linkRelationshipSizes = Doc.UserDoc().link_relationshipSizes as List<number>;
         const currRelationshipIndex = linkRelationshipList.indexOf(linkRelationship);
         const linkDescription = Field.toString(link.link_description as any as Field);
@@ -262,11 +262,11 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
         //thickness varies linearly from 3px to 12px for increasing link count
         const strokeWidth = linkSize === -1 ? '3px' : Math.floor(2 + 10 * (linkSize / Math.max(...linkRelationshipSizes))) + 'px';
 
-        if (link.layout_linkDisplayArrow === undefined) {
-            link.layout_linkDisplayArrow = false;
+        if (link.link_displayArrow === undefined) {
+            link.link_displayArrow = false;
         }
 
-        return link.opacity === 0 || !a.width || !b.width || (!link.layout_linkDisplay && !aActive && !bActive) ? null : (
+        return link.opacity === 0 || !a.width || !b.width || (!link.link_displayLine && !aActive && !bActive) ? null : (
             <>
                 <defs>
                     <marker id={`${link[Id] + 'arrowhead'}`} markerWidth="4" markerHeight="3" refX="0" refY="1.5" orient="auto">
@@ -295,7 +295,7 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
                     style={{ pointerEvents: 'visibleStroke', opacity: this._opacity, stroke, strokeWidth }}
                     onClick={this.onClickLine}
                     d={`M ${pt1[0]} ${pt1[1]} C ${pt1[0] + pt1norm[0]} ${pt1[1] + pt1norm[1]}, ${pt2[0] + pt2norm[0]} ${pt2[1] + pt2norm[1]}, ${pt2[0]} ${pt2[1]}`}
-                    markerEnd={link.layout_linkDisplayArrow ? `url(#${link[Id] + 'arrowhead'})` : ''}
+                    markerEnd={link.link_displayArrow ? `url(#${link[Id] + 'arrowhead'})` : ''}
                 />
                 {textX === undefined || !linkDescription ? null : (
                     <text filter={`url(#${link[Id] + 'background'})`} className="collectionfreeformlinkview-linkText" x={textX} y={textY} onPointerDown={this.pointerDown}>
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 811a77fa8..11151e74e 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1021,7 +1021,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
 
     @action
     zoom = (pointX: number, pointY: number, deltaY: number): void => {
-        if (this.Document._isGroup) return;
+        if (this.Document._isGroup || this.Document._freeform_noZoom) return;
         let deltaScale = deltaY > 0 ? 1 / 1.05 : 1.05;
         if (deltaScale < 0) deltaScale = -deltaScale;
         const [x, y] = this.getTransform().transformPoint(pointX, pointY);
@@ -1294,8 +1294,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 ScreenToLocalTransform={childLayout.z ? this.getContainerTransform : this.getTransform}
                 PanelWidth={childLayout[Width]}
                 PanelHeight={childLayout[Height]}
-                docFilters={this.childDocFilters}
-                docRangeFilters={this.childDocRangeFilters}
+                childFilters={this.childDocFilters}
+                childFiltersByRanges={this.childDocRangeFilters}
                 searchFilterDocs={this.searchFilterDocs}
                 isDocumentActive={this.props.childDocumentsActive?.() ? this.props.isDocumentActive : this.isContentActive}
                 isContentActive={this.props.childContentsActive ?? emptyFunction}
@@ -1317,7 +1317,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 dontRegisterView={this.props.dontRenderDocuments || this.props.dontRegisterView}
                 pointerEvents={this.pointerEvents}
                 //rotation={this.props.styleProvider?.(childLayout, this.props, StyleProp.JitterRotation) || 0}
-                //fitContentsToBox={this.props.fitContentsToBox || BoolCast(this.props.freezeChildDimensions)} // bcz: check this
+                //fitContentsToBox={this.props.fitContentsToBox || BoolCast(this.props.treeViewFreezeChildDimensions)} // bcz: check this
             />
         );
     }
@@ -1692,7 +1692,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         if ((e as any).handlePan || this.props.isAnnotationOverlay) return;
         (e as any).handlePan = true;
 
-        if (!this.layoutDoc._noAutoscroll && !this.props.renderDepth && this._marqueeRef) {
+        if (!this.layoutDoc._freeform_noAutoPan && !this.props.renderDepth && this._marqueeRef) {
             const dragX = e.detail.clientX;
             const dragY = e.detail.clientY;
             const bounds = this._marqueeRef?.getBoundingClientRect();
@@ -2007,8 +2007,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                             onKey={this.onKeyDown}
                             onDoubleClick={this.onChildDoubleClickHandler}
                             onBrowseClick={this.onBrowseClickHandler}
-                            docFilters={this.childDocFilters}
-                            docRangeFilters={this.childDocRangeFilters}
+                            childFilters={this.childDocFilters}
+                            childFiltersByRanges={this.childDocRangeFilters}
                             searchFilterDocs={this.searchFilterDocs}
                             isDocumentActive={this.props.childDocumentsActive?.() ? this.props.isDocumentActive : this.isContentActive}
                             isContentActive={this.props.childContentsActive ?? emptyFunction}
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index d50c8d2c4..534275610 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -522,7 +522,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
             followLinkToggle: true,
             _width: 200,
             _height: 200,
-            _layoutFitContentsToBox: true,
+            _layout_fitContentsToBox: true,
             _layout_showSidebar: true,
             title: 'overview',
         });
diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
index ca6b8705d..65578f214 100644
--- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
+++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
@@ -24,7 +24,7 @@ import './CollectionLinearView.scss';
 /**
  * CollectionLinearView is the class for rendering the horizontal collection
  * of documents, it useful for horizontal menus. It can either be expandable
- * or not using the linearViewExpandable field.
+ * or not using the linearView_Expandable field.
  * It is used in the following locations:
  * - It is used in the popup menu on the bottom left (see docButtons() in MainView.tsx)
  * - It is used for the context sensitive toolbar at the top (see contMenuButtons() in CollectionMenu.tsx)
@@ -46,7 +46,7 @@ export class CollectionLinearView extends CollectionSubView() {
 
     componentDidMount() {
         this._widthDisposer = reaction(
-            () => 5 + NumCast(this.rootDoc.linearBtnWidth, this.dimension()) + (this.layoutDoc.linearViewIsExpanded ? this.childDocs.filter(doc => !doc.hidden).reduce((tot, doc) => (doc[Width]() || this.dimension()) + tot + 4, 0) : 0),
+            () => 5 + NumCast(this.rootDoc.linearBtnWidth, this.dimension()) + (this.layoutDoc.linearView_IsExpanded ? this.childDocs.filter(doc => !doc.hidden).reduce((tot, doc) => (doc[Width]() || this.dimension()) + tot + 4, 0) : 0),
             width => this.childDocs.length && (this.layoutDoc._width = width),
             { fireImmediately: true }
         );
@@ -214,8 +214,8 @@ export class CollectionLinearView extends CollectionSubView() {
                     docViewPath={returnEmptyDoclist}
                     whenChildContentsActiveChanged={emptyFunction}
                     bringToFront={emptyFunction}
-                    docFilters={this.props.docFilters}
-                    docRangeFilters={this.props.docRangeFilters}
+                    childFilters={this.props.childFilters}
+                    childFiltersByRanges={this.props.childFiltersByRanges}
                     searchFilterDocs={this.props.searchFilterDocs}
                     hideResizeHandles={true}
                 />
@@ -226,7 +226,7 @@ export class CollectionLinearView extends CollectionSubView() {
     render() {
         const flexDir = StrCast(this.Document.flexDirection); // Specify direction of linear view content
         const flexGap = NumCast(this.Document.flexGap); // Specify the gap between linear view content
-        const isExpanded = BoolCast(this.layoutDoc.linearViewIsExpanded);
+        const isExpanded = BoolCast(this.layoutDoc.linearView_IsExpanded);
 
         const menuOpener = (
             <label
@@ -239,9 +239,9 @@ export class CollectionLinearView extends CollectionSubView() {
         );
 
         return (
-            <div className={`collectionLinearView-outer ${this.layoutDoc.linearViewSubMenu}`} style={{ backgroundColor: this.layoutDoc.linearViewIsExpanded ? undefined : 'transparent' }}>
+            <div className={`collectionLinearView-outer ${this.layoutDoc.linearView_SubMenu}`} style={{ backgroundColor: this.layoutDoc.linearView_IsExpanded ? undefined : 'transparent' }}>
                 <div className="collectionLinearView" ref={this.createDashEventsTarget} onContextMenu={this.myContextMenu} style={{ minHeight: this.dimension() }}>
-                    {!this.props.Document.linearViewExpandable ? null : (
+                    {!this.props.Document.linearView_Expandable ? null : (
                         <Tooltip title={<div className="dash-tooltip">{isExpanded ? 'Close' : 'Open'}</div>} placement="top">
                             {menuOpener}
                         </Tooltip>
@@ -259,11 +259,11 @@ export class CollectionLinearView extends CollectionSubView() {
                                 scriptContext: this.props.scriptContext,
                                 documentView: this.props.DocumentView?.(),
                             });
-                            this.layoutDoc.linearViewIsExpanded = this.addMenuToggle.current!.checked;
+                            this.layoutDoc.linearView_IsExpanded = this.addMenuToggle.current!.checked;
                         })}
                     />
 
-                    {!this.layoutDoc.linearViewIsExpanded ? null : (
+                    {!this.layoutDoc.linearView_IsExpanded ? null : (
                         <div
                             className="collectionLinearView-content"
                             style={{
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index 78d3d1b6e..34fa0343d 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -259,8 +259,8 @@ export class CollectionMulticolumnView extends CollectionSubView() {
                 hideDecorationTitle={this.props.childHideDecorationTitle?.()}
                 fitContentsToBox={this.props.fitContentsToBox}
                 focus={this.props.focus}
-                docFilters={this.childDocFilters}
-                docRangeFilters={this.childDocRangeFilters}
+                childFilters={this.childDocFilters}
+                childFiltersByRanges={this.childDocRangeFilters}
                 searchFilterDocs={this.searchFilterDocs}
                 dontRegisterView={this.props.dontRegisterView}
                 addDocument={this.props.addDocument}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index 4d61dc272..bab77ed48 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -258,8 +258,8 @@ export class CollectionMultirowView extends CollectionSubView() {
                 hideDecorationTitle={this.props.childHideDecorationTitle?.()}
                 fitContentsToBox={this.props.fitContentsToBox}
                 focus={this.props.focus}
-                docFilters={this.childDocFilters}
-                docRangeFilters={this.childDocRangeFilters}
+                childFilters={this.childDocFilters}
+                childFiltersByRanges={this.childDocRangeFilters}
                 searchFilterDocs={this.searchFilterDocs}
                 dontRegisterView={this.props.dontRegisterView}
                 addDocument={this.props.addDocument}
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
index 3a0c2c85c..52ebb7763 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
@@ -104,7 +104,7 @@
 
 .schema-header-row {
     cursor: grab;
-    justify-content: flex-end;
+    //justify-content: flex-end;
 
     .row-menu {
         display: flex;
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 36abad87e..15424de98 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -32,6 +32,7 @@ export enum ColumnType {
     Date,
     Image,
     RTF,
+    Enumeration,
     Any,
 }
 
@@ -42,6 +43,7 @@ export const FInfotoColType: { [key: string]: ColumnType } = {
     date: ColumnType.Date,
     image: ColumnType.Image,
     rtf: ColumnType.RTF,
+    enumeration: ColumnType.Enumeration,
 };
 
 const defaultColumnKeys: string[] = ['title', 'type', 'author', 'author_date', 'text'];
@@ -54,6 +56,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     private _makeNewColumn: boolean = false;
     private _documentOptions: DocumentOptions = new DocumentOptions();
     private _tableContentRef: HTMLDivElement | null = null;
+    private _menuTarget = React.createRef<HTMLDivElement>();
 
     static _rowHeight: number = 50;
     static _rowSingleLineHeight: number = 32;
@@ -77,6 +80,11 @@ export class CollectionSchemaView extends CollectionSubView() {
     @observable _filterSearchValue: string = '';
     @observable _selectedCell: [Doc, number] | undefined;
 
+    // target HTMLelement portal for showing a popup menu to edit cell values.
+    public get MenuTarget() {
+        return this._menuTarget.current;
+    }
+
     @computed get _selectedDocs() {
         return SelectionManager.Docs().filter(doc => Doc.AreProtosEqual(DocCast(doc.embedContainer), this.rootDoc));
     }
@@ -336,9 +344,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     dragColumn = (e: PointerEvent, index: number) => {
         const dragData = new DragManager.ColumnDragData(index);
         const dragEles = [this._colEles[index]];
-        this.childDocs.forEach(doc => {
-            dragEles.push(this._rowEles.get(doc).children[1].children[index]);
-        });
+        this.childDocs.forEach(doc => dragEles.push(this._rowEles.get(doc).children[1].children[index]));
         DragManager.StartColumnDrag(dragEles, dragData, e.x, e.y);
 
         document.removeEventListener('pointermove', this.highlightDropColumn);
@@ -352,24 +358,28 @@ export class CollectionSchemaView extends CollectionSubView() {
         return true;
     };
 
-    @action
-    highlightDropColumn = (e: PointerEvent) => {
-        e.stopPropagation();
-        const mouseX = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY)[0];
+    findDropIndex = (mouseX: number) => {
         let index: number | undefined;
         this.displayColumnWidths.reduce((total, curr, i) => {
             if (total <= mouseX && total + curr >= mouseX) {
-                if (mouseX <= total + curr / 2) index = i;
+                if (mouseX <= total + curr) index = i;
                 else index = i + 1;
             }
             return total + curr;
         }, CollectionSchemaView._rowMenuWidth);
+        return index;
+    };
 
+    @action
+    highlightDropColumn = (e: PointerEvent) => {
+        e.stopPropagation();
+        const mouseX = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY)[0];
+        const index = this.findDropIndex(mouseX);
         this._colEles.forEach((colRef, i) => {
             let leftStyle = '';
             let rightStyle = '';
-            if (i + 1 === index) rightStyle = `solid 2px ${Colors.MEDIUM_BLUE}`;
-            if (i === index && i === 0) leftStyle = `solid 2px ${Colors.MEDIUM_BLUE}`;
+            if (i + 1 === index) rightStyle = `solid 12px ${Colors.MEDIUM_BLUE}`;
+            if (i === index && i === 0) leftStyle = `solid 12px ${Colors.MEDIUM_BLUE}`;
             colRef.style.borderLeft = leftStyle;
             colRef.style.borderRight = rightStyle;
             this.childDocs.forEach(doc => {
@@ -426,15 +436,8 @@ export class CollectionSchemaView extends CollectionSubView() {
         if (de.complete.columnDragData) {
             e.stopPropagation();
             const mouseX = this.props.ScreenToLocalTransform().transformPoint(de.x, de.y)[0];
-            let index = de.complete.columnDragData.colIndex;
-            this.displayColumnWidths.reduce((total, curr, i) => {
-                if (total <= mouseX && total + curr >= mouseX) {
-                    if (mouseX <= total + curr / 2) index = i;
-                    else index = i + 1;
-                }
-                return total + curr;
-            }, CollectionSchemaView._rowMenuWidth);
-            this.moveColumn(de.complete.columnDragData.colIndex, index);
+            const index = this.findDropIndex(mouseX);
+            this.moveColumn(de.complete.columnDragData.colIndex, index ?? de.complete.columnDragData.colIndex);
 
             this._colEles.forEach((colRef, i) => {
                 colRef.style.borderLeft = '';
@@ -607,7 +610,7 @@ export class CollectionSchemaView extends CollectionSubView() {
         this._menuKeys = this.documentKeys.filter(value => value.toLowerCase().includes(this._menuValue.toLowerCase()));
     };
 
-    getFieldFilters = (field: string) => StrListCast(this.Document._docFilters).filter(filter => filter.split(':')[0] == field);
+    getFieldFilters = (field: string) => StrListCast(this.Document._childFilters).filter(filter => filter.split(':')[0] == field);
 
     removeFieldFilters = (field: string) => {
         this.getFieldFilters(field).forEach(filter => Doc.setDocFilter(this.Document, field, filter.split(':')[1], 'remove'));
@@ -760,7 +763,7 @@ export class CollectionSchemaView extends CollectionSubView() {
             }
         });
 
-        const filters = StrListCast(this.Document._docFilters);
+        const filters = StrListCast(this.Document._childFilters);
         return keyOptions.map(key => {
             let bool = false;
             if (filters !== undefined) {
@@ -832,6 +835,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     render() {
         return (
             <div className="collectionSchemaView" ref={(ele: HTMLDivElement | null) => this.createDashEventsTarget(ele)} onDrop={this.onExternalDrop.bind(this)}>
+                <div ref={this._menuTarget} style={{ background: 'red', top: 0, left: 0, position: 'absolute', zIndex: 10000 }}></div>
                 <div
                     className="schema-table"
                     onWheel={e => this.props.isContentActive() && e.stopPropagation()}
@@ -860,6 +864,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                                 openContextMenu={this.openContextMenu}
                                 dragColumn={this.dragColumn}
                                 setColRef={this.setColRef}
+                                isContentActive={this.props.isContentActive}
                             />
                         ))}
                     </div>
@@ -894,8 +899,8 @@ export class CollectionSchemaView extends CollectionSubView() {
                                 isContentActive={returnTrue}
                                 isDocumentActive={returnFalse}
                                 ScreenToLocalTransform={this.screenToLocal}
-                                docFilters={this.childDocFilters}
-                                docRangeFilters={this.childDocRangeFilters}
+                                childFilters={this.childDocFilters}
+                                childFiltersByRanges={this.childDocRangeFilters}
                                 searchFilterDocs={this.searchFilterDocs}
                                 styleProvider={DefaultStyleProvider}
                                 docViewPath={returnEmptyDoclist}
@@ -940,6 +945,7 @@ class CollectionSchemaViewDocs extends React.Component<CollectionSchemaViewDocsP
                                 LayoutTemplateString={SchemaRowBox.LayoutString(this.props.schema.props.fieldKey)}
                                 Document={doc}
                                 DataDoc={dataDoc}
+                                yPadding={index}
                                 renderDepth={this.props.schema.props.renderDepth + 1}
                                 PanelWidth={this.tableWidthFunc}
                                 PanelHeight={this.props.rowHeight}
@@ -949,8 +955,8 @@ class CollectionSchemaViewDocs extends React.Component<CollectionSchemaViewDocsP
                                 enableDragWhenActive={true}
                                 onClickScriptDisable="always"
                                 focus={this.props.schema.focusDocument}
-                                docFilters={this.props.schema.childDocFilters}
-                                docRangeFilters={this.props.schema.childDocRangeFilters}
+                                childFilters={this.props.schema.childDocFilters}
+                                childFiltersByRanges={this.props.schema.childDocRangeFilters}
                                 searchFilterDocs={this.props.schema.searchFilterDocs}
                                 rootSelected={this.props.schema.rootSelected}
                                 ScreenToLocalTransform={this.childScreenToLocal(index)}
diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
index 46c2f622b..65e47f441 100644
--- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
@@ -12,6 +12,7 @@ export interface SchemaColumnHeaderProps {
     columnIndex: number;
     sortField: string;
     sortDesc: boolean;
+    isContentActive: (outsideReaction?: boolean | undefined) => boolean | undefined;
     setSort: (field: string | undefined, desc?: boolean) => void;
     removeColumn: (index: number) => void;
     rowHeight: () => number;
@@ -44,7 +45,7 @@ export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps>
 
     @action
     onPointerDown = (e: React.PointerEvent) => {
-        setupMoveUpEvents(this, e, e => this.props.dragColumn(e, this.props.columnIndex), emptyFunction, emptyFunction, false);
+        this.props.isContentActive(true) && setupMoveUpEvents(this, e, e => this.props.dragColumn(e, this.props.columnIndex), emptyFunction, emptyFunction, false);
     };
 
     render() {
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 978b65053..4f3503751 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -7,7 +7,7 @@ import { Doc } from '../../../../fields/Doc';
 import { BoolCast } from '../../../../fields/Types';
 import { DragManager } from '../../../util/DragManager';
 import { SnappingManager } from '../../../util/SnappingManager';
-import { undoable, undoBatch } from '../../../util/UndoManager';
+import { undoable } from '../../../util/UndoManager';
 import { ViewBoxBaseComponent } from '../../DocComponent';
 import { Colors } from '../../global/globalEnums';
 import { OpenWhere } from '../../nodes/DocumentView';
@@ -15,6 +15,7 @@ import { FieldView, FieldViewProps } from '../../nodes/FieldView';
 import { CollectionSchemaView } from './CollectionSchemaView';
 import './CollectionSchemaView.scss';
 import { SchemaTableCell } from './SchemaTableCell';
+import { Transform } from '../../../util/Transform';
 
 @observer
 export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
@@ -143,6 +144,13 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
                             selectedCell={this.selectedCell}
                             setColumnValues={this.setColumnValues}
                             oneLine={BoolCast(this.schemaDoc?._singleLine)}
+                            menuTarget={this.schemaView.MenuTarget}
+                            transform={() => {
+                                const ind = index === this.schemaView.columnKeys.length - 1 ? this.schemaView.columnKeys.length - 3 : index;
+                                const x = this.schemaView?.displayColumnWidths.reduce((p, c, i) => (i <= ind ? p + c : p), 0);
+                                const y = (this.props.yPadding ?? 0) * this.props.PanelHeight();
+                                return new Transform(x + CollectionSchemaView._rowMenuWidth, y, 1);
+                            }}
                         />
                     ))}
                 </div>
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 876693474..97264508c 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -1,4 +1,5 @@
-import React = require('react');
+import * as React from 'react';
+import Select, { MenuPlacement } from 'react-select';
 import { action, computed, observable } from 'mobx';
 import { observer } from 'mobx-react';
 import { extname } from 'path';
@@ -6,12 +7,11 @@ import DatePicker from 'react-datepicker';
 import { DateField } from '../../../../fields/DateField';
 import { Doc, DocListCast, Field } from '../../../../fields/Doc';
 import { RichTextField } from '../../../../fields/RichTextField';
-import { BoolCast, Cast, DateCast, DocCast, FieldValue } from '../../../../fields/Types';
+import { BoolCast, Cast, DateCast, DocCast, FieldValue, StrCast } from '../../../../fields/Types';
 import { ImageField } from '../../../../fields/URLField';
 import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnZero, Utils } from '../../../../Utils';
 import { FInfo } from '../../../documents/Documents';
 import { DocFocusOrOpen } from '../../../util/DocumentManager';
-import { dropActionType } from '../../../util/DragManager';
 import { Transform } from '../../../util/Transform';
 import { undoable, undoBatch } from '../../../util/UndoManager';
 import { EditableView } from '../../EditableView';
@@ -21,7 +21,7 @@ import { FieldView, FieldViewProps } from '../../nodes/FieldView';
 import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox';
 import { KeyValueBox } from '../../nodes/KeyValueBox';
 import { DefaultStyleProvider } from '../../StyleProvider';
-import { ColumnType, FInfotoColType } from './CollectionSchemaView';
+import { CollectionSchemaView, ColumnType, FInfotoColType } from './CollectionSchemaView';
 import './CollectionSchemaView.scss';
 
 export interface SchemaTableCellProps {
@@ -41,6 +41,9 @@ export interface SchemaTableCellProps {
     oneLine?: boolean; // whether all input should fit on one line vs allowing textare multiline inputs
     allowCRs?: boolean; // allow carriage returns in text input (othewrise CR ends the edit)
     finishEdit?: () => void; // notify container that edit is over (eg. to hide view in DashFieldView)
+    options?: string[];
+    menuTarget: HTMLDivElement | null;
+    transform: () => Transform;
 }
 
 @observer
@@ -64,8 +67,8 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
         const color = protoCount === 0 || (fieldKey.startsWith('_') && Document[fieldKey] === undefined) ? 'black' : 'blue';
         const textDecoration = color !== 'black' && parenCount ? 'underline' : '';
         const fieldProps: FieldViewProps = {
-            docFilters: returnEmptyFilter,
-            docRangeFilters: returnEmptyFilter,
+            childFilters: returnEmptyFilter,
+            childFiltersByRanges: returnEmptyFilter,
             searchFilterDocs: returnEmptyDoclist,
             styleProvider: DefaultStyleProvider,
             docViewPath: returnEmptyDoclist,
@@ -129,15 +132,15 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
     }
 
     get getCellType() {
+        const columnTypeStr = this.props.getFinfo(this.props.fieldKey)?.fieldType;
         const cellValue = this.props.Document[this.props.fieldKey];
         if (cellValue instanceof ImageField) return ColumnType.Image;
         if (cellValue instanceof DateField) return ColumnType.Date;
         if (cellValue instanceof RichTextField) return ColumnType.RTF;
         if (typeof cellValue === 'number') return ColumnType.Any;
-        if (typeof cellValue === 'string') return ColumnType.Any;
+        if (typeof cellValue === 'string' && columnTypeStr !== 'enumeration') return ColumnType.Any;
         if (typeof cellValue === 'boolean') return ColumnType.Boolean;
 
-        const columnTypeStr = this.props.getFinfo(this.props.fieldKey)?.fieldType;
         if (columnTypeStr && columnTypeStr in FInfotoColType) {
             return FInfotoColType[columnTypeStr];
         }
@@ -152,6 +155,7 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
             case ColumnType.Image: return <SchemaImageCell {...this.props} />;
             case ColumnType.Boolean: return <SchemaBoolCell {...this.props} />;
             case ColumnType.RTF: return <SchemaRTFCell {...this.props} />;
+            case ColumnType.Enumeration: return <SchemaEnumerationCell {...this.props} options={this.props.getFinfo(this.props.fieldKey)?.values?.map(val => val.toString())} />;
             case ColumnType.Date: // return <SchemaDateCell {...this.props} />;
             default:  return this.defaultCellContent;
         }
@@ -311,3 +315,38 @@ export class SchemaBoolCell extends React.Component<SchemaTableCellProps> {
         );
     }
 }
+@observer
+export class SchemaEnumerationCell extends React.Component<SchemaTableCellProps> {
+    @computed get selected() {
+        const selected: [Doc, number] | undefined = this.props.selectedCell();
+        return this.props.isRowActive() && selected?.[0] === this.props.Document && selected[1] === this.props.col;
+    }
+    render() {
+        const { color, textDecoration, fieldProps, cursor, pointerEvents } = SchemaTableCell.renderProps(this.props);
+        const options = this.props.options?.map(facet => ({ value: facet, label: facet }));
+        return (
+            <div className="schemaSelectionCell" style={{ display: 'flex', color, textDecoration, cursor, pointerEvents }}>
+                <div style={{ width: '100%' }}>
+                    <Select
+                        styles={{
+                            menuPortal: base => ({
+                                ...base,
+                                left: 0,
+                                top: 0,
+                                transform: `translate(${this.props.transform().TranslateX}px, ${this.props.transform().TranslateY}px)`,
+                                width: Number(base.width) * this.props.transform().Scale,
+                                zIndex: 9999,
+                            }),
+                        }}
+                        menuPortalTarget={this.props.menuTarget}
+                        menuPosition={'absolute'}
+                        placeholder={StrCast(this.props.Document[this.props.fieldKey], 'select...')}
+                        options={options}
+                        isMulti={false}
+                        onChange={val => KeyValueBox.SetField(this.props.Document, this.props.fieldKey.replace(/^_/, ''), `"${val?.value ?? ''}"`)}
+                    />
+                </div>
+            </div>
+        );
+    }
+}
diff --git a/src/client/views/linking/LinkMenuGroup.tsx b/src/client/views/linking/LinkMenuGroup.tsx
index b9d56541a..8324a97d9 100644
--- a/src/client/views/linking/LinkMenuGroup.tsx
+++ b/src/client/views/linking/LinkMenuGroup.tsx
@@ -25,7 +25,7 @@ export class LinkMenuGroup extends React.Component<LinkMenuGroupProps> {
 
     getBackgroundColor = (): string => {
         const link_relationshipList = StrListCast(Doc.UserDoc().link_relationshipList);
-        const linkColorList = StrListCast(Doc.UserDoc().linkColorList);
+        const linkColorList = StrListCast(Doc.UserDoc().link_ColorList);
         let color = 'white';
         // if this link's relationship property is not default "link", set its color
         if (link_relationshipList) {
diff --git a/src/client/views/linking/LinkPopup.tsx b/src/client/views/linking/LinkPopup.tsx
index 5f2d4a7b6..664a0fa4f 100644
--- a/src/client/views/linking/LinkPopup.tsx
+++ b/src/client/views/linking/LinkPopup.tsx
@@ -89,8 +89,8 @@ export class LinkPopup extends React.Component<LinkPopupProps> {
                         docViewPath={returnEmptyDoclist}
                         whenChildContentsActiveChanged={emptyFunction}
                         bringToFront={emptyFunction}
-                        docFilters={returnEmptyFilter}
-                        docRangeFilters={returnEmptyFilter}
+                        childFilters={returnEmptyFilter}
+                        childFiltersByRanges={returnEmptyFilter}
                         searchFilterDocs={returnEmptyDoclist}
                     />
                 </div>
diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
index 60480ac33..d84e34d52 100644
--- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx
+++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
@@ -57,7 +57,7 @@ export class TableBox extends React.Component<TableBoxProps> {
                                                             DragManager.StartAnchorAnnoDrag([header.current!], new DragManager.AnchorAnnoDragData(this.props.docView()!, sourceAnchorCreator, targetCreator), downX, downY, {
                                                                 dragComplete: e => {
                                                                     if (!e.aborted && e.annoDragData && e.annoDragData.linkSourceDoc && e.annoDragData.dropDocument && e.linkDocument) {
-                                                                        e.linkDocument.layout_linkDisplay = true;
+                                                                        e.linkDocument.link_displayLine = true;
                                                                         // e.annoDragData.linkSourceDoc.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this.props.rootDoc;
                                                                         // e.annoDragData.linkSourceDoc.followLinkZoom = false;
                                                                     }
diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx
index bd1952ecb..7723a088d 100644
--- a/src/client/views/nodes/DocumentLinksButton.tsx
+++ b/src/client/views/nodes/DocumentLinksButton.tsx
@@ -71,7 +71,9 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
             e,
             this.onLinkButtonMoved,
             emptyFunction,
-            action((e, doubleTap) => doubleTap && DocumentView.showBackLinks(this.props.View.rootDoc)),
+            action((e, doubleTap) => {
+                doubleTap && DocumentView.showBackLinks(this.props.View.rootDoc);
+            }),
             undefined,
             undefined,
             action(() => (DocumentLinksButton.LinkEditorDocView = this.props.View))
@@ -191,7 +193,7 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
 
     @computed get filteredLinks() {
         const results = [] as Doc[];
-        const filters = this.props.View.props.docFilters();
+        const filters = this.props.View.props.childFilters();
         Array.from(new Set<Doc>(this.props.View.allLinks)).forEach(link => {
             if (DocUtils.FilterDocs([link], filters, []).length || DocUtils.FilterDocs([link.link_anchor_2 as Doc], filters, []).length || DocUtils.FilterDocs([link.link_anchor_1 as Doc], filters, []).length) {
                 results.push(link);
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 687683e6e..461066b1b 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -168,8 +168,8 @@ export interface DocumentViewSharedProps {
     setTitleFocus?: () => void;
     focus: DocFocusFunc;
     layout_fitWidth?: (doc: Doc) => boolean | undefined;
-    docFilters: () => string[];
-    docRangeFilters: () => string[];
+    childFilters: () => string[];
+    childFiltersByRanges: () => string[];
     searchFilterDocs: () => Doc[];
     layout_showTitle?: () => string;
     whenChildContentsActiveChanged: (isActive: boolean) => void;
@@ -192,7 +192,7 @@ export interface DocumentViewSharedProps {
     hideCaptions?: boolean;
     ignoreAutoHeight?: boolean;
     forceAutoHeight?: boolean;
-    disableDocBrushing?: boolean; // should highlighting for this view be disabled when same document in another view is hovered over.
+    disableBrushing?: boolean; // should highlighting for this view be disabled when same document in another view is hovered over.
     onClickScriptDisable?: 'never' | 'always'; // undefined = only when selected
     enableDragWhenActive?: boolean;
     waitForDoubleClickToClick?: () => 'never' | 'always' | undefined;
@@ -664,7 +664,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
 
     @action
     onContextMenu = (e?: React.MouseEvent, pageX?: number, pageY?: number) => {
-        if (e && this.rootDoc._hideContextMenu && Doc.noviceMode) {
+        if (e && this.rootDoc._layout_hideContextMenu && Doc.noviceMode) {
             e.preventDefault();
             e.stopPropagation();
             //!this.props.isSelected(true) && SelectionManager.SelectView(this.props.DocumentView(), false);
@@ -880,7 +880,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
             ? true
             : false;
     };
-    docFilters = () => [...this.props.docFilters(), ...StrListCast(this.layoutDoc.docFilters)];
+    childFilters = () => [...this.props.childFilters(), ...StrListCast(this.layoutDoc.childFilters)];
     contentPointerEvents = () => (!this.disableClickScriptFunc && this.onClickHandler ? 'none' : this.pointerEvents);
     @computed get contents() {
         TraceMobx();
@@ -912,7 +912,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                     docViewPath={this.props.viewPath}
                     thumbShown={this.thumbShown}
                     setContentView={this.setContentView}
-                    docFilters={this.docFilters}
+                    childFilters={this.childFilters}
                     NativeDimScaling={this.props.NativeDimScaling}
                     PanelHeight={this.panelHeight}
                     setHeight={!this.props.suppressSetHeight ? this.setHeight : undefined}
@@ -924,7 +924,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                     setTitleFocus={this.setTitleFocus}
                     layout_fieldKey={this.finalLayoutKey}
                 />
-                {this.layoutDoc.hideAllLinks ? null : this.allLinkEndpoints}
+                {this.layoutDoc.layout_hideAllLinks ? null : this.allLinkEndpoints}
             </div>
         );
     }
@@ -960,12 +960,12 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
         TraceMobx();
         return LinkManager.Instance.getAllRelatedLinks(this.rootDoc);
     }
-    hideLink = computedFn((link: Doc) => () => (link.layout_linkDisplay = false));
+    hideLink = computedFn((link: Doc) => () => (link.link_displayLine = false));
     @computed get allLinkEndpoints() {
         // the small blue dots that mark the endpoints of links
         TraceMobx();
         if (this.props.hideLinkAnchors || this.layoutDoc.layout_hideLinkAnchors || this.props.dontRegisterView || this.layoutDoc.layout_unrendered) return null;
-        const filtered = DocUtils.FilterDocs(this.directLinks, this.props.docFilters?.() ?? [], []).filter(d => d.layout_linkDisplay);
+        const filtered = DocUtils.FilterDocs(this.directLinks, this.props.childFilters?.() ?? [], []).filter(d => d.link_displayLine);
         return filtered.map(link => (
             <div className="documentView-anchorCont" key={link[Id]}>
                 <DocumentView
@@ -1013,7 +1013,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                 gumStream = stream;
                 recorder = new MediaRecorder(stream);
                 recorder.ondataavailable = async (e: any) => {
-                    const [{ result }] = await Networking.UploadFilesToServer({file: e.data});
+                    const [{ result }] = await Networking.UploadFilesToServer({ file: e.data });
                     if (!(result instanceof Error)) {
                         const audioField = new AudioField(result.accessPaths.agnostic.client);
                         const audioAnnos = Cast(dataDoc[field + '-audioAnnotations'], listSpec(AudioField), null);
@@ -1296,13 +1296,13 @@ export class DocumentView extends React.Component<DocumentViewProps> {
     }
 
     // shows a stacking view collection (by default, but the user can change) of all documents linked to the source
-    public static showBackLinks(linkSource: Doc) {
-        const docId = Doc.CurrentUserEmail + Doc.GetProto(linkSource)[Id] + '-pivotish';
+    public static showBackLinks(linkAnchor: Doc) {
+        const docId = Doc.CurrentUserEmail + Doc.GetProto(linkAnchor)[Id] + '-pivotish';
         // prettier-ignore
-        DocServer.GetRefField(docId).then(docx => docx instanceof Doc &&
+        DocServer.GetRefField(docId).then(docx =>
             LightboxView.SetLightboxDoc(
-                docx || // reuse existing pivot view of documents, or else create a new collection
-                Docs.Create.StackingDocument([], { title: linkSource.title + '-pivot', _width: 500, _height: 500, linkSource, updateContentsScript: ScriptField.MakeScript('updateLinkCollection(self)') }, docId)
+                (docx as Doc) ?? // reuse existing pivot view of documents, or else create a new collection
+                Docs.Create.StackingDocument([], { title: linkAnchor.title + '-pivot', _width: 500, _height: 500, target: linkAnchor, updateContentsScript: ScriptField.MakeScript('updateLinkCollection(self, self.target)') }, docId)
             )
         );
     }
@@ -1490,8 +1490,8 @@ export class DocumentView extends React.Component<DocumentViewProps> {
             // increase max auto height if document has been resized to be greater than current max
             () => NumCast(this.layoutDoc._height),
             action(height => {
-                const docMax = NumCast(this.layoutDoc.docMaxAutoHeight);
-                if (docMax && docMax < height) this.layoutDoc.docMaxAutoHeight = height;
+                const docMax = NumCast(this.layoutDoc.layout_maxAutoHeight);
+                if (docMax && docMax < height) this.layoutDoc.layout_maxAutoHeight = height;
             })
         );
         !BoolCast(this.props.Document.dontRegisterView, this.props.dontRegisterView) && DocumentManager.Instance.AddView(this);
@@ -1577,16 +1577,16 @@ ScriptingGlobals.add(function toggleDetail(dv: DocumentView, detailLayoutKeySuff
     else dv.switchViews(true, detailLayoutKeySuffix, undefined, true);
 });
 
-ScriptingGlobals.add(function updateLinkCollection(linkCollection: Doc) {
-    const linkSource = Cast(linkCollection.linkSource, Doc, null);
+ScriptingGlobals.add(function updateLinkCollection(linkCollection: Doc, linkSource: Doc) {
     const collectedLinks = DocListCast(Doc.GetProto(linkCollection).data);
     let wid = linkSource[Width]();
+    let embedding:Doc|undefined;
     const links = LinkManager.Links(linkSource);
     links.forEach(link => {
         const other = LinkManager.getOppositeAnchor(link, linkSource);
-        const otherdoc = !other ? undefined : other.annotationOn ? Cast(other.annotationOn, Doc, null) : other;
+        const otherdoc = DocCast(other?.annotationOn ?? other);
         if (otherdoc && !collectedLinks?.some(d => Doc.AreProtosEqual(d, otherdoc))) {
-            const embedding = Doc.MakeEmbedding(otherdoc);
+            embedding = Doc.MakeEmbedding(otherdoc);
             embedding.x = wid;
             embedding.y = 0;
             embedding._lockedPosition = false;
@@ -1594,5 +1594,6 @@ ScriptingGlobals.add(function updateLinkCollection(linkCollection: Doc) {
             Doc.AddDocToList(Doc.GetProto(linkCollection), 'data', embedding);
         }
     });
+    embedding && DocServer.UPDATE_SERVER_CACHE();// if a new embedding was made, update the client's server cache so that it will not come back as a promise
     return links;
 });
diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx
index 4e348c67c..64f25cb22 100644
--- a/src/client/views/nodes/KeyValuePair.tsx
+++ b/src/client/views/nodes/KeyValuePair.tsx
@@ -57,8 +57,8 @@ export class KeyValuePair extends React.Component<KeyValuePairProps> {
         const props: FieldViewProps = {
             Document: this.props.doc,
             DataDoc: this.props.doc,
-            docFilters: returnEmptyFilter,
-            docRangeFilters: returnEmptyFilter,
+            childFilters: returnEmptyFilter,
+            childFiltersByRanges: returnEmptyFilter,
             searchFilterDocs: returnEmptyDoclist,
             styleProvider: DefaultStyleProvider,
             docViewPath: returnEmptyDoclist,
diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx
index 73823041c..52f3575cb 100644
--- a/src/client/views/nodes/LabelBox.tsx
+++ b/src/client/views/nodes/LabelBox.tsx
@@ -87,8 +87,8 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps & LabelBoxProp
         const params = {
             rotateText: null,
             fontSizeFactor: 1,
-            minimumFontSize: NumCast(this.rootDoc._minFontSize, 8),
-            maximumFontSize: NumCast(this.rootDoc._maxFontSize, 1000),
+            minimumFontSize: NumCast(this.rootDoc._label_minFontSize, 8),
+            maximumFontSize: NumCast(this.rootDoc._label_maxFontSize, 1000),
             limitingDimension: 'both',
             horizontalAlign: 'center',
             verticalAlign: 'center',
diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx
index f38ef634c..e86b881a8 100644
--- a/src/client/views/nodes/LinkAnchorBox.tsx
+++ b/src/client/views/nodes/LinkAnchorBox.tsx
@@ -53,7 +53,7 @@ export class LinkAnchorBox extends ViewBoxBaseComponent<FieldViewProps>() {
             } else {
                 this.rootDoc[this.fieldKey + '_x'] = ((pt[0] - bounds.left) / bounds.width) * 100;
                 this.rootDoc[this.fieldKey + '_y'] = ((pt[1] - bounds.top) / bounds.height) * 100;
-                this.rootDoc.layout_autoMoveAnchors = false;
+                this.rootDoc.link_autoMoveAnchors = false;
             }
         }
         return false;
@@ -68,7 +68,7 @@ export class LinkAnchorBox extends ViewBoxBaseComponent<FieldViewProps>() {
         const y = NumCast(this.rootDoc[this.fieldKey + '_y'], 100);
         const background = this.props.styleProvider?.(this.dataDoc, this.props, StyleProp.BackgroundColor + ':anchor');
         const anchor = this.fieldKey === 'link_anchor_1' ? 'link_anchor_2' : 'link_anchor_1';
-        const anchorScale = !this.dataDoc[this.fieldKey + '_useLinkSmallAnchor'] && (x === 0 || x === 100 || y === 0 || y === 100) ? 1 : 0.25;
+        const anchorScale = !this.dataDoc[this.fieldKey + '_useSmallAnchor'] && (x === 0 || x === 100 || y === 0 || y === 100) ? 1 : 0.25;
         const targetTitle = StrCast((this.dataDoc[anchor] as Doc)?.title);
         const selView = SelectionManager.Views().lastElement()?.props.LayoutTemplateString?.includes('link_anchor_1')
             ? 'link_anchor_1'
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx
index 079e1b56d..86191de63 100644
--- a/src/client/views/nodes/LinkDocPreview.tsx
+++ b/src/client/views/nodes/LinkDocPreview.tsx
@@ -268,8 +268,8 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
                             addDocTab={returnFalse}
                             pinToPres={returnFalse}
                             dontRegisterView={true}
-                            docFilters={returnEmptyFilter}
-                            docRangeFilters={returnEmptyFilter}
+                            childFilters={returnEmptyFilter}
+                            childFiltersByRanges={returnEmptyFilter}
                             searchFilterDocs={returnEmptyDoclist}
                             renderDepth={0}
                             suppressSetHeight={true}
diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx
index f03954789..93e54ffb7 100644
--- a/src/client/views/nodes/MapBox/MapBox.tsx
+++ b/src/client/views/nodes/MapBox/MapBox.tsx
@@ -394,7 +394,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         return StrCast(this.layoutDoc._layout_sidebarWidthPercent, '0%');
     }
     @computed get sidebarColor() {
-        return StrCast(this.layoutDoc.sidebarColor, StrCast(this.layoutDoc[this.props.fieldKey + '_backgroundColor'], '#e4e4e4'));
+        return StrCast(this.layoutDoc.sidebar_color, StrCast(this.layoutDoc[this.props.fieldKey + '_backgroundColor'], '#e4e4e4'));
     }
 
     /**
@@ -550,8 +550,8 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     panelWidth = () => this.props.PanelWidth() / (this.props.NativeDimScaling?.() || 1) - this.sidebarWidth();
     panelHeight = () => this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1);
     scrollXf = () => this.props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._layout_scrollTop));
-    transparentFilter = () => [...this.props.docFilters(), Utils.IsTransparentFilter()];
-    opaqueFilter = () => [...this.props.docFilters(), Utils.IsOpaqueFilter()];
+    transparentFilter = () => [...this.props.childFilters(), Utils.IsTransparentFilter()];
+    opaqueFilter = () => [...this.props.childFilters(), Utils.IsOpaqueFilter()];
     infoWidth = () => this.props.PanelWidth() / 5;
     infoHeight = () => this.props.PanelHeight() / 5;
     anchorMenuClick = () => this._sidebarRef.current?.anchorMenuClick;
@@ -601,7 +601,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     };
     bingMapReady = (map: any) => (this._bingMap = map.map);
     render() {
-        const renderAnnotations = (docFilters?: () => string[]) => null;
+        const renderAnnotations = (childFilters?: () => string[]) => null;
         return (
             <div className="mapBox" ref={this._ref}>
                 <div
diff --git a/src/client/views/nodes/MapBox/MapBox2.tsx b/src/client/views/nodes/MapBox/MapBox2.tsx
index 18fcc951a..72f37b62c 100644
--- a/src/client/views/nodes/MapBox/MapBox2.tsx
+++ b/src/client/views/nodes/MapBox/MapBox2.tsx
@@ -391,7 +391,7 @@ export class MapBox2 extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         return StrCast(this.layoutDoc._layout_sidebarWidthPercent, '0%');
     }
     @computed get sidebarColor() {
-        return StrCast(this.layoutDoc.sidebarColor, StrCast(this.layoutDoc[this.props.fieldKey + '_backgroundColor'], '#e4e4e4'));
+        return StrCast(this.layoutDoc.sidebar_color, StrCast(this.layoutDoc[this.props.fieldKey + '_backgroundColor'], '#e4e4e4'));
     }
 
     /**
@@ -547,8 +547,8 @@ export class MapBox2 extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     panelWidth = () => this.props.PanelWidth() / (this.props.NativeDimScaling?.() || 1) - this.sidebarWidth();
     panelHeight = () => this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1);
     scrollXf = () => this.props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._layout_scrollTop));
-    transparentFilter = () => [...this.props.docFilters(), Utils.IsTransparentFilter()];
-    opaqueFilter = () => [...this.props.docFilters(), Utils.IsOpaqueFilter()];
+    transparentFilter = () => [...this.props.childFilters(), Utils.IsTransparentFilter()];
+    opaqueFilter = () => [...this.props.childFilters(), Utils.IsOpaqueFilter()];
     infoWidth = () => this.props.PanelWidth() / 5;
     infoHeight = () => this.props.PanelHeight() / 5;
     anchorMenuClick = () => this._sidebarRef.current?.anchorMenuClick;
@@ -558,7 +558,7 @@ export class MapBox2 extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         return (window as any).Microsoft.Maps;
     }
     render() {
-        const renderAnnotations = (docFilters?: () => string[]) => null;
+        const renderAnnotations = (childFilters?: () => string[]) => null;
         return (
             <div className="MapBox2" ref={this._ref}>
                 <div
diff --git a/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx b/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx
index 6b26f494b..577101445 100644
--- a/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx
+++ b/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx
@@ -59,7 +59,7 @@ export class MapBoxInfoWindow extends React.Component<MapBoxInfoWindowProps & Vi
                             fieldKey="data"
                             NativeWidth={returnZero}
                             NativeHeight={returnZero}
-                            docFilters={returnEmptyFilter}
+                            childFilters={returnEmptyFilter}
                             setHeight={emptyFunction}
                             isAnnotationOverlay={false}
                             select={emptyFunction}
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 6ee1b67f2..c210176b0 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -441,7 +441,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         return PDFBox.sidebarResizerWidth + nativeDiff * (this.props.NativeDimScaling?.() || 1);
     };
     @undoBatch
-    toggleSidebarType = () => (this.rootDoc.sidebarViewType = this.rootDoc.sidebarViewType === CollectionViewType.Freeform ? CollectionViewType.Stacking : CollectionViewType.Freeform);
+    toggleSidebarType = () => (this.rootDoc.sidebar_collectionType = this.rootDoc.sidebar_collectionType === CollectionViewType.Freeform ? CollectionViewType.Stacking : CollectionViewType.Freeform);
     specificContextMenu = (e: React.MouseEvent): void => {
         const cm = ContextMenu.Instance;
         const options = cm.findByDescription('Options...');
@@ -557,7 +557,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         };
         return (
             <div className={'formattedTextBox-sidebar' + (Doc.ActiveTool !== InkTool.None ? '-inking' : '')} style={{ width: '100%', right: 0, backgroundColor: `white` }}>
-                {renderComponent(StrCast(this.layoutDoc.sidebarViewType))}
+                {renderComponent(StrCast(this.layoutDoc.sidebar_collectionType))}
             </div>
         );
     }
diff --git a/src/client/views/nodes/QueryBox.scss b/src/client/views/nodes/QueryBox.scss
deleted file mode 100644
index b5f90aa1e..000000000
--- a/src/client/views/nodes/QueryBox.scss
+++ /dev/null
@@ -1,5 +0,0 @@
-.queryBox, .queryBox-dragging {
-    width: 100%;
-    height: 100%; 
-    position: absolute;
-}
\ No newline at end of file
diff --git a/src/client/views/nodes/QueryBox.tsx b/src/client/views/nodes/QueryBox.tsx
deleted file mode 100644
index 1b6056be6..000000000
--- a/src/client/views/nodes/QueryBox.tsx
+++ /dev/null
@@ -1,38 +0,0 @@
-// import React = require("react");
-// import { IReactionDisposer } from "mobx";
-// import { observer } from "mobx-react";
-// import { documentSchema } from "../../../new_fields/documentSchemas";
-// import { Id } from '../../../new_fields/FieldSymbols';
-// import { makeInterface, listSpec } from "../../../new_fields/Schema";
-// import { StrCast, Cast } from "../../../new_fields/Types";
-// import { ViewBoxAnnotatableComponent } from '../DocComponent';
-// import { SearchBox } from "../search/SearchBox";
-// import { FieldView, FieldViewProps } from './FieldView';
-// import "./QueryBox.scss";
-// import { List } from "../../../new_fields/List";
-// import { SnappingManager } from "../../util/SnappingManager";
-
-// type QueryDocument = makeInterface<[typeof documentSchema]>;
-// const QueryDocument = makeInterface(documentSchema);
-
-// @observer
-// export class QueryBox extends ViewBoxAnnotatableComponent<FieldViewProps, QueryDocument>(QueryDocument) {
-//     public static LayoutString(fieldKey: string) { return FieldView.LayoutString(QueryBox, fieldKey); }
-//     _docListChangedReaction: IReactionDisposer | undefined;
-//     componentDidMount() {
-//     }
-
-//     componentWillUnmount() {
-//         this._docListChangedReaction?.();
-//     }
-
-//     render() {
-//         const dragging = !SnappingManager.GetIsDragging() ? "" : "-dragging";
-//         return <div className={`queryBox${dragging}`} onWheel={(e) => e.stopPropagation()} >
-            
-//             <SearchBox  Document={this.props.Document}  />
-//         </div >;
-//     }
-// }
-
-// //<SearchBox id={this.props.Document[Id]} sideBar={side} Document={this.props.Document} searchQuery={StrCast(this.dataDoc.searchQuery)} filterQuery={this.dataDoc.filterQuery} />
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 34dcde23b..1f52c2d92 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -913,7 +913,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
     marqueeFitScaling = () => ((this.props.NativeDimScaling?.() || 1) * this.heightPercent) / 100;
     marqueeOffset = () => [((this.panelWidth() / 2) * (1 - this.heightPercent / 100)) / (this.heightPercent / 100), 0];
 
-    timelineDocFilter = () => [`_timelineLabel:true,${Utils.noRecursionHack}:x`];
+    timelineDocFilter = () => [`_isTimelineLabel:true,${Utils.noRecursionHack}:x`];
 
     // renders video controls
     componentUI = (boundsLeft: number, boundsTop: number) => {
@@ -1082,7 +1082,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                             PanelHeight={this.panelHeight}
                             isAnyChildContentActive={returnFalse}
                             ScreenToLocalTransform={this.screenToLocalTransform}
-                            docFilters={this.timelineDocFilter}
+                            childFilters={this.timelineDocFilter}
                             select={emptyFunction}
                             focus={emptyFunction}
                             NativeDimScaling={returnOne}
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 48f77469f..2ff0245d2 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -900,7 +900,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         const previewScale = this._previewNativeWidth ? 1 - this.sidebarWidth() / this._previewNativeWidth : 1;
         const pointerEvents = this.layoutDoc._lockedPosition ? 'none' : (this.props.pointerEvents?.() as any);
         const scale = previewScale * (this.props.NativeDimScaling?.() || 1);
-        const renderAnnotations = (docFilters: () => string[]) => (
+        const renderAnnotations = (childFilters: () => string[]) => (
             <CollectionFreeFormView
                 {...this.props}
                 setContentView={this.setInnerContent}
@@ -919,7 +919,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 NativeDimScaling={returnOne}
                 focus={this.focus}
                 dropAction="embed"
-                docFilters={docFilters}
+                childFilters={childFilters}
                 select={emptyFunction}
                 isAnyChildContentActive={returnFalse}
                 bringToFront={emptyFunction}
@@ -995,8 +995,8 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     panelHeight = () => this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1);
     scrollXf = () => this.props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._layout_scrollTop));
     anchorMenuClick = () => this._sidebarRef.current?.anchorMenuClick;
-    transparentFilter = () => [...this.props.docFilters(), Utils.IsTransparentFilter()];
-    opaqueFilter = () => [...this.props.docFilters(), Utils.noDragsDocFilter, ...(DragManager.docsBeingDragged.length ? [] : [Utils.IsOpaqueFilter()])];
+    transparentFilter = () => [...this.props.childFilters(), Utils.IsTransparentFilter()];
+    opaqueFilter = () => [...this.props.childFilters(), Utils.noDragsDocFilter, ...(DragManager.docsBeingDragged.length ? [] : [Utils.IsOpaqueFilter()])];
     childStyleProvider = (doc: Doc | undefined, props: Opt<DocumentViewProps>, property: string): any => {
         if (doc instanceof Doc && property === StyleProp.PointerEvents) {
             if (this.inlineTextAnnotations.includes(doc)) return 'none';
diff --git a/src/client/views/nodes/button/FontIconBox.tsx b/src/client/views/nodes/button/FontIconBox.tsx
index 601759dbb..5bba51ec8 100644
--- a/src/client/views/nodes/button/FontIconBox.tsx
+++ b/src/client/views/nodes/button/FontIconBox.tsx
@@ -95,7 +95,7 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
 
     // Determining UI Specs
     @computed get label() {
-        return StrCast(this.rootDoc.label, StrCast(this.rootDoc.title));
+        return StrCast(this.rootDoc.icon_label, StrCast(this.rootDoc.title));
     }
     Icon = (color: string) => {
         const icon = StrCast(this.dataDoc[this.fieldKey ?? 'icon'] ?? this.dataDoc.icon, 'user') as any;
diff --git a/src/client/views/nodes/formattedText/DashDocView.tsx b/src/client/views/nodes/formattedText/DashDocView.tsx
index 1d41eb379..48f4c2afd 100644
--- a/src/client/views/nodes/formattedText/DashDocView.tsx
+++ b/src/client/views/nodes/formattedText/DashDocView.tsx
@@ -217,8 +217,8 @@ export class DashDocViewInternal extends React.Component<IDashDocViewInternal> {
                     whenChildContentsActiveChanged={returnFalse}
                     bringToFront={emptyFunction}
                     dontRegisterView={false}
-                    docFilters={this.props.tbox?.props.docFilters}
-                    docRangeFilters={this.props.tbox?.props.docRangeFilters}
+                    childFilters={this.props.tbox?.props.childFilters}
+                    childFiltersByRanges={this.props.tbox?.props.childFiltersByRanges}
                     searchFilterDocs={this.props.tbox?.props.searchFilterDocs}
                 />
             </div>
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 105fb9003..115777c18 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -132,7 +132,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
         return this._showSidebar ? '20%' : StrCast(this.layoutDoc._layout_sidebarWidthPercent, '0%');
     }
     @computed get sidebarColor() {
-        return StrCast(this.layoutDoc.sidebarColor, StrCast(this.layoutDoc[this.fieldKey + '_backgroundColor'], '#e4e4e4'));
+        return StrCast(this.layoutDoc.sidebar_color, StrCast(this.layoutDoc[this.fieldKey + '_backgroundColor'], '#e4e4e4'));
     }
     @computed get layout_autoHeight() {
         return (this.props.forceAutoHeight || this.layoutDoc._layout_autoHeight) && !this.props.ignoreAutoHeight;
@@ -811,9 +811,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
             icon: !this.Document._layout_noSidebar ? 'eye-slash' : 'eye',
         });
         uicontrols.push({
-            description: (this.Document._layout_altContentUI ? 'Hide' : 'Show') + ' Alt Content UI',
-            event: () => (this.layoutDoc._layout_altContentUI = !this.layoutDoc._layout_altContentUI),
-            icon: !this.Document._layout_altContentUI ? 'eye-slash' : 'eye',
+            description: (this.Document._layout_enableAltContentUI ? 'Hide' : 'Show') + ' Alt Content UI',
+            event: () => (this.layoutDoc._layout_enableAltContentUI = !this.layoutDoc._layout_enableAltContentUI),
+            icon: !this.Document._layout_enableAltContentUI ? 'eye-slash' : 'eye',
         });
         uicontrols.push({ description: 'Show Highlights...', noexpand: true, subitems: highlighting, icon: 'hand-point-right' });
         !Doc.noviceMode &&
@@ -1741,7 +1741,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
 
         const state = this._editorView!.state;
         const curText = state.doc.textBetween(0, state.doc.content.size, ' \n');
-        if (this.layoutDoc.sidebarViewType === 'translation' && !this.fieldKey.includes('translation') && curText.endsWith(' ') && curText !== this._lastText) {
+        if (this.layoutDoc.sidebar_collectionType === 'translation' && !this.fieldKey.includes('translation') && curText.endsWith(' ') && curText !== this._lastText) {
             try {
                 translateGoogleApi(curText, { from: 'en', to: 'es' }).then((result1: any) => {
                     setTimeout(
@@ -1837,7 +1837,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                 return toNum(height) + Math.max(0, toNum(marginTop)) + Math.max(0, toNum(marginBottom));
             };
             const proseHeight = !this.ProseRef ? 0 : children.reduce((p, child) => p + toHgt(child), margins);
-            const scrollHeight = this.ProseRef && Math.min(NumCast(this.layoutDoc.docMaxAutoHeight, proseHeight), proseHeight);
+            const scrollHeight = this.ProseRef && Math.min(NumCast(this.layoutDoc.layout_maxAutoHeight, proseHeight), proseHeight);
             if (this.props.setHeight && scrollHeight && !this.props.dontRegisterView) {
                 // if top === 0, then the text box is growing upward (as the overlay caption) which doesn't contribute to the height computation
                 const setScrollHeight = () => (this.rootDoc[this.fieldKey + '_scrollHeight'] = scrollHeight);
@@ -1949,19 +1949,19 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                         fitContentsToBox={this.fitContentsToBox}
                         noSidebar={true}
                         treeViewHideTitle={true}
-                        fieldKey={this.layoutDoc.sidebarViewType === 'translation' ? `${this.fieldKey}_translation` : `${this.fieldKey}_sidebar`}
+                        fieldKey={this.layoutDoc.sidebar_collectionType === 'translation' ? `${this.fieldKey}_translation` : `${this.fieldKey}_sidebar`}
                     />
                 </div>
             );
         };
         return (
             <div className={'formattedTextBox-sidebar' + (Doc.ActiveTool !== InkTool.None ? '-inking' : '')} style={{ width: `${this.layout_sidebarWidthPercent}`, backgroundColor: `${this.sidebarColor}` }}>
-                {renderComponent(StrCast(this.layoutDoc.sidebarViewType))}
+                {renderComponent(StrCast(this.layoutDoc.sidebar_collectionType))}
             </div>
         );
     }
     cycleAlternateText = () => {
-        if (this.layoutDoc._layout_altContentUI) {
+        if (this.layoutDoc._layout_enableAltContentUI) {
             const usePath = this.rootDoc[`${this.props.fieldKey}_usePath`];
             this.rootDoc[`_${this.props.fieldKey}_usePath`] = usePath === undefined ? 'alternate' : usePath === 'alternate' ? 'alternate:hover' : undefined;
         }
@@ -2016,7 +2016,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
         const active = this.props.isContentActive() || this.props.isSelected();
         const selected = active;
         const scale = (this.props.NativeDimScaling?.() || 1) * NumCast(this.layoutDoc._freeform_scale, 1);
-        const rounded = StrCast(this.layoutDoc.borderRounding) === '100%' ? '-rounded' : '';
+        const rounded = StrCast(this.layoutDoc.layout_borderRounding) === '100%' ? '-rounded' : '';
         const interactive = (Doc.ActiveTool === InkTool.None || SnappingManager.GetIsDragging()) && (this.layoutDoc.z || !this.layoutDoc._lockedPosition);
         if (!selected && FormattedTextBoxComment.textBox === this) setTimeout(FormattedTextBoxComment.Hide);
         const minimal = this.props.ignoreAutoHeight;
@@ -2096,7 +2096,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                     {this.noSidebar || this.props.dontSelectOnLoad || !this.SidebarShown || this.layout_sidebarWidthPercent === '0%' ? null : this.sidebarCollection}
                     {this.noSidebar || this.Document._layout_noSidebar || this.props.dontSelectOnLoad || this.Document._createDocOnCR ? null : this.sidebarHandle}
                     {this.audioHandle}
-                    {this.layoutDoc._layout_altContentUI ? this.overlayAlternateIcon : null}
+                    {this.layoutDoc._layout_enableAltContentUI ? this.overlayAlternateIcon : null}
                 </div>
             </div>
         );
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index 884811317..ac20126f1 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -488,8 +488,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
         }
 
         if ((pinDataTypes?.filters && activeItem.presDocFilters !== undefined) || (!pinDataTypes && activeItem.presDocFilters !== undefined)) {
-            if (bestTarget.docFilters !== activeItem.presDocFilters) {
-                bestTarget.docFilters = ObjectField.MakeCopy(activeItem.presDocFilters as ObjectField) || new List<string>([]);
+            if (bestTarget.childFilters !== activeItem.presDocFilters) {
+                bestTarget.childFilters = ObjectField.MakeCopy(activeItem.presDocFilters as ObjectField) || new List<string>([]);
                 changed = true;
             }
         }
@@ -651,7 +651,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
                     )
                 );
             if (pinProps.pinData.type_collection) pinDoc.presViewType = targetDoc._type_collection;
-            if (pinProps.pinData.filters) pinDoc.presDocFilters = ObjectField.MakeCopy(targetDoc.docFilters as ObjectField);
+            if (pinProps.pinData.filters) pinDoc.presDocFilters = ObjectField.MakeCopy(targetDoc.childFilters as ObjectField);
             if (pinProps.pinData.pivot) pinDoc.presPivotField = targetDoc._pivotField;
             if (pinProps.pinData.pannable) {
                 pinDoc.presPanX = NumCast(targetDoc._freeform_panX);
@@ -2078,10 +2078,10 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
         // prettier-ignore
         switch (layout) {
             case 'blank': return Docs.Create.FreeformDocument([], { title: input ? input : 'Blank slide', _width: 400, _height: 225, x, y });
-            case 'title': return Docs.Create.FreeformDocument([title(), subtitle()], { title: input ? input : 'Title slide', _width: 400, _height: 225, _layoutFitContentsToBox: true, x, y });
-            case 'header': return Docs.Create.FreeformDocument([header()], { title: input ? input : 'Section header', _width: 400, _height: 225, _layoutFitContentsToBox: true, x, y });
-            case 'content': return Docs.Create.FreeformDocument([contentTitle(), content()], { title: input ? input : 'Title and content', _width: 400, _height: 225, _layoutFitContentsToBox: true, x, y });
-            case 'twoColumns': return Docs.Create.FreeformDocument([contentTitle(), content1(), content2()], { title: input ? input : 'Title and two columns', _width: 400, _height: 225, _layoutFitContentsToBox: true, x, y })
+            case 'title': return Docs.Create.FreeformDocument([title(), subtitle()], { title: input ? input : 'Title slide', _width: 400, _height: 225, _layout_fitContentsToBox: true, x, y });
+            case 'header': return Docs.Create.FreeformDocument([header()], { title: input ? input : 'Section header', _width: 400, _height: 225, _layout_fitContentsToBox: true, x, y });
+            case 'content': return Docs.Create.FreeformDocument([contentTitle(), content()], { title: input ? input : 'Title and content', _width: 400, _height: 225, _layout_fitContentsToBox: true, x, y });
+            case 'twoColumns': return Docs.Create.FreeformDocument([contentTitle(), content1(), content2()], { title: input ? input : 'Title and two columns', _width: 400, _height: 225, _layout_fitContentsToBox: true, x, y })
         }
     };
 
diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx
index 154c879a0..34e069046 100644
--- a/src/client/views/nodes/trails/PresElementBox.tsx
+++ b/src/client/views/nodes/trails/PresElementBox.tsx
@@ -107,8 +107,8 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
                     ScreenToLocalTransform={Transform.Identity}
                     renderDepth={this.props.renderDepth + 1}
                     docViewPath={returnEmptyDoclist}
-                    docFilters={this.props.docFilters}
-                    docRangeFilters={this.props.docRangeFilters}
+                    childFilters={this.props.childFilters}
+                    childFiltersByRanges={this.props.childFiltersByRanges}
                     searchFilterDocs={this.props.searchFilterDocs}
                     rootSelected={returnTrue}
                     addDocument={returnFalse}
@@ -377,9 +377,9 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
             const recording = Docs.Create.WebCamDocument('', {
                 _width: 384,
                 _height: 216,
-                hideDocumentButtonBar: true,
+                layout_hideDocumentButtonBar: true,
                 layout_hideDecorationTitle: true,
-                hideOpenButton: true,
+                layout_hideOpenButton: true,
                 // hideDeleteButton: true,
                 cloneFieldFilter: new List<string>(['isSystem']),
             });
@@ -522,7 +522,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
                         style={{
                             display: 'infline-block',
                             backgroundColor: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor),
-                            //boxShadow: presBoxColor && presBoxColor !== 'white' && presBoxColor !== 'transparent' ? (isCurrent ? '0 0 0px 1.5px' + presBoxColor : undefined) : undefined,
+                            //layout_boxShadow: presBoxColor && presBoxColor !== 'white' && presBoxColor !== 'transparent' ? (isCurrent ? '0 0 0px 1.5px' + presBoxColor : undefined) : undefined,
                             border: presBoxColor && presBoxColor !== 'white' && presBoxColor !== 'transparent' ? (isCurrent ? presBoxColor + ' solid 2.5px' : undefined) : undefined,
                         }}>
                         <div
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index bc0cad636..dd202418b 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -91,7 +91,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
     @observable isAnnotating = false;
     // key where data is stored
     @computed get allAnnotations() {
-        return DocUtils.FilterDocs(DocListCast(this.props.dataDoc[this.props.fieldKey + '_annotations']), this.props.docFilters(), this.props.docRangeFilters());
+        return DocUtils.FilterDocs(DocListCast(this.props.dataDoc[this.props.fieldKey + '_annotations']), this.props.childFilters(), this.props.childFiltersByRanges());
     }
     @computed get inlineTextAnnotations() {
         return this.allAnnotations.filter(a => a.textInlineAnnotations);
@@ -513,8 +513,8 @@ export class PDFViewer extends React.Component<IViewerProps> {
     overlayTransform = () => this.scrollXf().scale(1 / NumCast(this.props.layoutDoc._freeform_scale, 1));
     panelWidth = () => this.props.PanelWidth() / (this.props.NativeDimScaling?.() || 1);
     panelHeight = () => this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1);
-    transparentFilter = () => [...this.props.docFilters(), Utils.IsTransparentFilter()];
-    opaqueFilter = () => [...this.props.docFilters(), Utils.noDragsDocFilter, ...(DragManager.docsBeingDragged.length ? [] : [Utils.IsOpaqueFilter()])];
+    transparentFilter = () => [...this.props.childFilters(), Utils.IsTransparentFilter()];
+    opaqueFilter = () => [...this.props.childFilters(), Utils.noDragsDocFilter, ...(DragManager.docsBeingDragged.length ? [] : [Utils.IsOpaqueFilter()])];
     childStyleProvider = (doc: Doc | undefined, props: Opt<DocumentViewProps>, property: string): any => {
         if (doc instanceof Doc && property === StyleProp.PointerEvents) {
             if (this.inlineTextAnnotations.includes(doc)) return 'none';
@@ -523,7 +523,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
         return this.props.styleProvider?.(doc, props, property);
     };
 
-    renderAnnotations = (docFilters: () => string[], mixBlendMode?: any, display?: string) => (
+    renderAnnotations = (childFilters: () => string[], mixBlendMode?: any, display?: string) => (
         <div
             className="pdfViewerDash-overlay"
             style={{
@@ -550,7 +550,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
                 isAnyChildContentActive={returnFalse}
                 isAnnotationOverlayScrollable={true}
                 dropAction="embed"
-                docFilters={docFilters}
+                childFilters={childFilters}
                 select={emptyFunction}
                 bringToFront={emptyFunction}
                 styleProvider={this.childStyleProvider}
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 72eeedcff..92ae64567 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -1415,18 +1415,18 @@ export namespace Doc {
     }
     export function setDocRangeFilter(container: Opt<Doc>, key: string, range?: number[]) {
         if (!container) return;
-        const docRangeFilters = Cast(container._docRangeFilters, listSpec('string'), []);
-        for (let i = 0; i < docRangeFilters.length; i += 3) {
-            if (docRangeFilters[i] === key) {
-                docRangeFilters.splice(i, 3);
+        const childFiltersByRanges = Cast(container._childFiltersByRanges, listSpec('string'), []);
+        for (let i = 0; i < childFiltersByRanges.length; i += 3) {
+            if (childFiltersByRanges[i] === key) {
+                childFiltersByRanges.splice(i, 3);
                 break;
             }
         }
         if (range !== undefined) {
-            docRangeFilters.push(key);
-            docRangeFilters.push(range[0].toString());
-            docRangeFilters.push(range[1].toString());
-            container._docRangeFilters = new List<string>(docRangeFilters);
+            childFiltersByRanges.push(key);
+            childFiltersByRanges.push(range[0].toString());
+            childFiltersByRanges.push(range[1].toString());
+            container._childFiltersByRanges = new List<string>(childFiltersByRanges);
         }
     }
 
@@ -1435,35 +1435,35 @@ export namespace Doc {
     // based on the modifiers :"check", "x", undefined
     export function setDocFilter(container: Opt<Doc>, key: string, value: any, modifiers: 'remove' | 'match' | 'check' | 'x' | 'exists' | 'unset', toggle?: boolean, fieldPrefix?: string, append: boolean = true) {
         if (!container) return;
-        const filterField = '_' + (fieldPrefix ? fieldPrefix + '_' : '') + 'docFilters';
-        const docFilters = StrListCast(container[filterField]);
+        const filterField = '_' + (fieldPrefix ? fieldPrefix + '_' : '') + 'childFilters';
+        const childFilters = StrListCast(container[filterField]);
         runInAction(() => {
-            for (let i = 0; i < docFilters.length; i++) {
-                const fields = docFilters[i].split(':'); // split key:value:modifier
+            for (let i = 0; i < childFilters.length; i++) {
+                const fields = childFilters[i].split(':'); // split key:value:modifier
                 if (fields[0] === key && (fields[1] === value || modifiers === 'match' || (fields[2] === 'match' && modifiers === 'remove'))) {
                     if (fields[2] === modifiers && modifiers && fields[1] === value) {
                         if (toggle) modifiers = 'remove';
                         else return;
                     }
-                    docFilters.splice(i, 1);
-                    container[filterField] = new List<string>(docFilters);
+                    childFilters.splice(i, 1);
+                    container[filterField] = new List<string>(childFilters);
                     break;
                 }
             }
-            if (!docFilters.length && modifiers === 'match' && value === undefined) {
+            if (!childFilters.length && modifiers === 'match' && value === undefined) {
                 container[filterField] = undefined;
             } else if (modifiers !== 'remove') {
-                !append && (docFilters.length = 0);
-                docFilters.push(key + ':' + value + ':' + modifiers);
-                container[filterField] = new List<string>(docFilters);
+                !append && (childFilters.length = 0);
+                childFilters.push(key + ':' + value + ':' + modifiers);
+                container[filterField] = new List<string>(childFilters);
             }
         });
     }
     export function readDocRangeFilter(doc: Doc, key: string) {
-        const docRangeFilters = Cast(doc._docRangeFilters, listSpec('string'), []);
-        for (let i = 0; i < docRangeFilters.length; i += 3) {
-            if (docRangeFilters[i] === key) {
-                return [Number(docRangeFilters[i + 1]), Number(docRangeFilters[i + 2])];
+        const childFiltersByRanges = Cast(doc._childFiltersByRanges, listSpec('string'), []);
+        for (let i = 0; i < childFiltersByRanges.length; i += 3) {
+            if (childFiltersByRanges[i] === key) {
+                return [Number(childFiltersByRanges[i + 1]), Number(childFiltersByRanges[i + 2])];
             }
         }
     }
diff --git a/src/fields/documentSchemas.ts b/src/fields/documentSchemas.ts
index 7a0a18929..757d507be 100644
--- a/src/fields/documentSchemas.ts
+++ b/src/fields/documentSchemas.ts
@@ -55,8 +55,8 @@ export const documentSchema = createSchema({
 
     // appearance properties on the data document
     backgroundColor: 'string', // background color of document
-    borderRounding: 'string', // border radius rounding of document
-    boxShadow: 'string', // the amount of shadow around the perimeter of a document
+    layout_borderRounding: 'string', // border radius rounding of document
+    layout_boxShadow: 'string', // the amount of shadow around the perimeter of a document
     color: 'string', // foreground color of document
     freeform_fitContentsToBox: 'boolean', // whether freeform view contents should be zoomed/panned to fill the area of the document view box
     fontSize: 'string',
@@ -86,13 +86,13 @@ export const documentSchema = createSchema({
     onDragStart: ScriptField, // script to run when document is dragged (without being selected).  the script should return the Doc to be dropped.
     followLinkLocation: 'string', // flag for where to place content when following a click interaction (e.g., add:right, lightbox, default, )
     hideLinkButton: 'boolean', // whether the blue link counter button should be hidden
-    hideAllLinks: 'boolean', // whether all individual blue anchor dots should be hidden
-    layout_linkDisplay: 'boolean', // whether a link connection should be shown between link anchor endpoints.
+    layout_hideAllLinks: 'boolean', // whether all individual blue anchor dots should be hidden
+    link_displayLine: 'boolean', // whether a link connection should be shown between link anchor endpoints.
     isLightbox: 'boolean', // whether the marked object will display addDocTab() calls that target "lightbox" destinations
     layers: listSpec('string'), // which layers the document is part of
     _lockedPosition: 'boolean', // whether the document can be moved (dragged)
     _lockedTransform: 'boolean', // whether a freeformview can pan/zoom
-    layout_linkDisplayArrow: 'boolean', // toggles directed arrows
+    link_displayArrow: 'boolean', // toggles directed arrows
 
     // drag drop properties
     _stayInCollection: 'boolean', // whether document can be dropped into a different collection
diff --git a/src/fields/util.ts b/src/fields/util.ts
index 62f27c7d2..f365adf4b 100644
--- a/src/fields/util.ts
+++ b/src/fields/util.ts
@@ -16,7 +16,7 @@ import { PrefetchProxy, ProxyField } from './Proxy';
 import { RefField } from './RefField';
 import { RichTextField } from './RichTextField';
 import { SchemaHeaderField } from './SchemaHeaderField';
-import { ComputedField } from './ScriptField';
+import { ComputedField, ScriptField } from './ScriptField';
 import { ScriptCast, StrCast } from './Types';
 
 function _readOnlySetter(): never {
@@ -69,10 +69,12 @@ const _setterImpl = action(function (target: any, prop: string | symbol | number
 
     if (writeToDoc) {
         if (value === undefined) {
-            delete target[FieldKeys][prop];
+            target[FieldKeys] && delete target[FieldKeys][prop]; // Lists don't have a FieldKeys field
             delete target.__fieldTuples[prop];
         } else {
-            target[FieldKeys][prop] = true;
+            // bcz: uncomment to see if server is being updated
+            // console.log(prop + ' = ' + value + '(' + curValue + ')');
+            target[FieldKeys] && (target[FieldKeys][prop] = true); // Lists don't have a FieldKeys field
             target.__fieldTuples[prop] = value;
         }
 
diff --git a/src/mobile/AudioUpload.tsx b/src/mobile/AudioUpload.tsx
index c3423e2a5..7a1dde9fb 100644
--- a/src/mobile/AudioUpload.tsx
+++ b/src/mobile/AudioUpload.tsx
@@ -25,8 +25,8 @@ export class AudioUpload extends React.Component {
                 title: 'mobile audio',
                 _width: 300,
                 _height: 300,
-                _layoutFitContentsToBox: true,
-                boxShadow: '0 0',
+                _layout_fitContentsToBox: true,
+                layout_boxShadow: '0 0',
             }),
             Doc
         )
@@ -54,7 +54,7 @@ export class AudioUpload extends React.Component {
                             Doc
                         ) as Doc,
                     ],
-                    { title: 'mobile audio', _width: 300, _height: 300, _layoutFitContentsToBox: true, boxShadow: '0 0' }
+                    { title: 'mobile audio', _width: 300, _height: 300, _layout_fitContentsToBox: true, layout_boxShadow: '0 0' }
                 ),
                 Doc
             )
@@ -110,8 +110,8 @@ export class AudioUpload extends React.Component {
                         pinToPres={emptyFunction}
                         rootSelected={returnTrue}
                         removeDocument={undefined}
-                        docFilters={returnEmptyFilter}
-                        docRangeFilters={returnEmptyFilter}
+                        childFilters={returnEmptyFilter}
+                        childFiltersByRanges={returnEmptyFilter}
                         searchFilterDocs={returnEmptyDoclist}
                         ScreenToLocalTransform={Transform.Identity}
                         PanelWidth={() => 600}
diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx
index 471dc568b..584a7b432 100644
--- a/src/mobile/MobileInterface.tsx
+++ b/src/mobile/MobileInterface.tsx
@@ -402,8 +402,8 @@ export class MobileInterface extends React.Component {
                     docViewPath={returnEmptyDoclist}
                     whenChildContentsActiveChanged={emptyFunction}
                     bringToFront={emptyFunction}
-                    docFilters={returnEmptyFilter}
-                    docRangeFilters={returnEmptyFilter}
+                    childFilters={returnEmptyFilter}
+                    childFiltersByRanges={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
                 />
             </div>
-- 
cgit v1.2.3-70-g09d2


From 72dad52c4fea5a2fccabacbb6a49ca1494093954 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 22 Jun 2023 10:14:26 -0400
Subject: cleaned up dragging - abort presItem drags properly, fix naming for
 drag/dropAction, small fix undo of drag removeproperties, dragging in/out of
 headerBar,  fixed isContentActive to avoid SnappingManager.GetIsDragging. 
 fixed resizing videos.

---
 src/client/documents/Documents.ts                  | 49 +++++------
 src/client/util/CurrentUserUtils.ts                | 81 +++++++++---------
 src/client/util/DragManager.ts                     | 38 ++++-----
 src/client/util/DropConverter.ts                   |  8 +-
 src/client/util/UndoManager.ts                     | 19 ++---
 src/client/views/DashboardView.tsx                 |  6 +-
 src/client/views/DocComponent.tsx                  |  6 +-
 src/client/views/DocumentDecorations.tsx           |  8 +-
 src/client/views/GestureOverlay.tsx                | 95 +---------------------
 src/client/views/MainView.tsx                      | 12 ++-
 src/client/views/Palette.scss                      | 30 -------
 src/client/views/Palette.tsx                       | 69 ----------------
 src/client/views/PropertiesView.tsx                |  1 -
 src/client/views/StyleProvider.tsx                 |  1 +
 src/client/views/TemplateMenu.tsx                  |  5 +-
 .../views/collections/CollectionCarouselView.tsx   |  4 +-
 .../views/collections/CollectionNoteTakingView.tsx |  6 +-
 .../views/collections/CollectionPileView.tsx       | 11 ++-
 .../collections/CollectionStackedTimeline.scss     |  2 +-
 .../collections/CollectionStackedTimeline.tsx      | 10 ++-
 .../views/collections/CollectionStackingView.tsx   | 18 ++--
 src/client/views/collections/CollectionSubView.tsx | 10 +--
 .../views/collections/CollectionTimeView.tsx       |  2 -
 .../views/collections/CollectionTreeView.tsx       | 14 ++--
 src/client/views/collections/CollectionView.tsx    |  5 +-
 src/client/views/collections/TabDocView.tsx        |  1 -
 src/client/views/collections/TreeView.tsx          | 29 ++++---
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 11 ++-
 .../collections/collectionFreeForm/MarqueeView.tsx |  1 -
 .../collectionGrid/CollectionGridView.tsx          |  2 +-
 .../collectionLinear/CollectionLinearView.tsx      | 40 ++-------
 .../CollectionMulticolumnView.tsx                  | 18 ++--
 .../CollectionMultirowView.tsx                     | 19 +++--
 .../collectionSchema/CollectionSchemaView.tsx      |  3 +-
 .../collections/collectionSchema/SchemaRowBox.tsx  |  8 +-
 .../collectionSchema/SchemaTableCell.tsx           |  2 +-
 src/client/views/linking/LinkMenuItem.tsx          |  2 +-
 src/client/views/linking/LinkPopup.tsx             |  1 -
 src/client/views/nodes/ComparisonBox.scss          |  2 +-
 src/client/views/nodes/ComparisonBox.tsx           | 80 ++++++++++++------
 src/client/views/nodes/DocumentView.tsx            | 52 +++++++-----
 src/client/views/nodes/FieldView.tsx               |  2 +-
 src/client/views/nodes/ImageBox.tsx                |  4 +-
 src/client/views/nodes/KeyValueBox.tsx             |  8 +-
 src/client/views/nodes/KeyValuePair.tsx            |  1 -
 src/client/views/nodes/LinkAnchorBox.tsx           |  2 +-
 src/client/views/nodes/MapBox/MapBox.tsx           |  5 +-
 src/client/views/nodes/MapBox/MapBox2.tsx          |  2 +-
 src/client/views/nodes/PDFBox.tsx                  |  2 -
 src/client/views/nodes/WebBox.tsx                  | 14 +++-
 .../views/nodes/formattedText/FormattedTextBox.tsx | 21 ++---
 src/client/views/nodes/trails/PresBox.tsx          |  4 +-
 src/client/views/nodes/trails/PresElementBox.tsx   | 13 +--
 src/client/views/pdf/PDFViewer.tsx                 | 18 ++--
 src/fields/Doc.ts                                  |  2 +-
 src/fields/documentSchemas.ts                      | 10 +--
 src/fields/util.ts                                 |  4 +-
 57 files changed, 356 insertions(+), 537 deletions(-)
 delete mode 100644 src/client/views/Palette.scss
 delete mode 100644 src/client/views/Palette.tsx

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index ffde9fe1b..a61ef1da3 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -25,7 +25,7 @@ import { DirectoryImportBox } from '../util/Import & Export/DirectoryImportBox';
 import { FollowLinkScript } from '../util/LinkFollower';
 import { LinkManager } from '../util/LinkManager';
 import { ScriptingGlobals } from '../util/ScriptingGlobals';
-import { undoable, undoBatch, UndoManager } from '../util/UndoManager';
+import { undoable, UndoManager } from '../util/UndoManager';
 import { CollectionDockingView } from '../views/collections/CollectionDockingView';
 import { DimUnit } from '../views/collections/collectionMulticolumn/CollectionMulticolumnView';
 import { CollectionView } from '../views/collections/CollectionView';
@@ -184,7 +184,8 @@ export class DocumentOptions {
     opacity?: NUMt = new NumInfo('document opacity');
     viewTransitionTime?: NUMt = new NumInfo('transition duration for view parameters');
     dontRegisterView?: BOOLt = new BoolInfo('are views of this document registered so that they can be found when following links, etc');
-    dontUndo?: BOOLt = new BoolInfo('whether button clicks should be undoable (true for Undo/Redo/and sidebar) AND whether modifications to document are undoable (true for linearview menu buttons to prevent open/close from entering undo stack)');
+    _undoIgnoreFields?: List<string>; //'fields that should not be added to the undo stack (opacity for Undo/Redo/and sidebar) AND whether modifications to document are undoable (true for linearview menu buttons to prevent open/close from entering undo stack)'
+    undoIgnoreFields?: List<string>; //'fields that should not be added to the undo stack (opacity for Undo/Redo/and sidebar) AND whether modifications to document are undoable (true for linearview menu buttons to prevent open/close from entering undo stack)'
     _headerHeight?: NUMt = new NumInfo('height of document header used for displaying title');
     _headerFontSize?: NUMt = new NumInfo('font size of header of custom notes');
     _headerPointerEvents?: PEVt = new PEInfo('types of events the header of a custom text document can consume');
@@ -355,20 +356,19 @@ export class DocumentOptions {
     waitForDoubleClickToClick?: 'always' | 'never' | 'default'; // whether a click function wait for double click to expire.  'default' undefined = wait only if there's a click handler, "never" = never wait, "always" = alway wait
     onPointerDown?: ScriptField;
     onPointerUp?: ScriptField;
-    dragFactory_count?: NUMt = new NumInfo('number of items created from a drag button (used for setting title with incrementing index)', true);
     openFactoryLocation?: string; // an OpenWhere value to place the factory created document
     openFactoryAsDelegate?: BOOLt = new BoolInfo('create a delegate of the factory');
     _forceActive?: BOOLt = new BoolInfo('flag to handle pointer events when not selected (or otherwise active)');
-    enableDragWhenActive?: BOOLt = new BoolInfo('allow dragging even if document contentts are active (e.g., tree, groups)');
-    _stayInCollection?: BOOLt = new BoolInfo('whether the document should remain in its collection when someone tries to drag and drop it elsewhere');
+    _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.');
-    allowOverlayDrop?: BOOLt = new BoolInfo('can documents be dropped onto this document without using dragging title bar or holding down embed key (ctrl)?', true);
-    childDropAction?: DROPt = new DAInfo("what should happen to the source document when it's dropped onto a child of a collection ");
-    targetDropAction?: DROPt = new DAInfo('what should happen to the source document when ??? ');
+    childDragAction?: DROPt = new DAInfo('what should happen to the child documents when they are dragged fromt he 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");
     _dropAction?: DROPt = new DAInfo("what should happen to this document when it's dropped somewhere else");
-    _removeDropProperties?: List<string>; // list of properties that should be removed from a document when it is dropped.  e.g., a creator button may be forceActive to allow it be dragged, but the forceActive property can be removed from the dropped document
+    _dropPropertiesToRemove?: List<string>; // list of properties that should be removed from a document when it is dropped.  e.g., a creator button may be forceActive to allow it be dragged, but the forceActive property can be removed from the dropped document
     cloneFieldFilter?: List<string>; // fields not to copy when the document is clonedclipboard?: Doc;
-    dropConverter?: ScriptField; // script to run when documents are dropped on this Document.
+    dragAction?: DROPt = new DAInfo('how to drag document when it is active (e.g., tree, groups)');
+    dragFactory_count?: NUMt = new NumInfo('number of items created from a drag button (used for setting title with incrementing index)', true);
     dragFactory?: Doc; // document to create when dragging with a suitable onDragStart script
     clickFactory?: Doc; // document to create when clicking on a button with a suitable onClick script
     onDragStart?: ScriptField; //script to execute at start of drag operation --  e.g., when a "creator" button is dragged this script generates a different document to drop
@@ -536,7 +536,7 @@ export namespace Docs {
                         link_description: '',
                         layout_showCaption: 'link_description',
                         backgroundColor: 'lightblue', // lightblue is default color for linking dot and link documents text comment area
-                        _removeDropProperties: new List(['onClick']),
+                        _dropPropertiesToRemove: new List(['onClick']),
                     },
                 },
             ],
@@ -545,7 +545,7 @@ export namespace Docs {
                 {
                     data: new List<Doc>(),
                     layout: { view: EmptyBox, dataField: defaultDataKey },
-                    options: { childDropAction: 'embed', title: 'Global Link Database' },
+                    options: { title: 'Global Link Database' },
                 },
             ],
             [
@@ -553,7 +553,7 @@ export namespace Docs {
                 {
                     data: new List<Doc>(),
                     layout: { view: EmptyBox, dataField: defaultDataKey },
-                    options: { childDropAction: 'embed', title: 'Global Script Database' },
+                    options: { title: 'Global Script Database' },
                 },
             ],
             [
@@ -615,7 +615,7 @@ export namespace Docs {
                 DocumentType.FONTICON,
                 {
                     layout: { view: FontIconBox, dataField: 'icon' },
-                    options: { defaultDoubleClick: 'ignore', waitForDoubleClickToClick: 'never', enableDragWhenActive: true, layout_hideLinkButton: true, _width: 40, _height: 40 },
+                    options: { defaultDoubleClick: 'ignore', waitForDoubleClickToClick: 'never', layout_hideLinkButton: true, _width: 40, _height: 40 },
                 },
             ],
             [
@@ -659,7 +659,7 @@ export namespace Docs {
                 {
                     data: '',
                     layout: { view: ComparisonBox, dataField: defaultDataKey },
-                    options: { backgroundColor: 'gray', targetDropAction: 'embed' },
+                    options: { backgroundColor: 'gray', dropAction: 'move', waitForDoubleClickToClick: 'always' },
                 },
             ],
             [
@@ -667,7 +667,7 @@ export namespace Docs {
                 {
                     data: new List<Doc>(),
                     layout: { view: EmptyBox, dataField: defaultDataKey },
-                    options: { childDropAction: 'embed', title: 'Global Group Database' },
+                    options: { childDragAction: 'embed', title: 'Global Group Database' },
                 },
             ],
             [
@@ -1066,12 +1066,7 @@ export namespace Docs {
         }
 
         export function PileDocument(documents: Array<Doc>, options: DocumentOptions, id?: string) {
-            return InstanceFromProto(
-                Prototypes.get(DocumentType.COL),
-                new List(documents),
-                { enableDragWhenActive: true, _forceActive: true, _freeform_noZoom: true, _freeform_noAutoPan: true, ...options, _type_collection: CollectionViewType.Pile },
-                id
-            );
+            return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { dropAction: 'move', _forceActive: true, _freeform_noZoom: true, _freeform_noAutoPan: true, ...options, _type_collection: CollectionViewType.Pile }, id);
         }
 
         export function LinearDocument(documents: Array<Doc>, options: DocumentOptions, id?: string) {
@@ -1523,7 +1518,7 @@ export namespace DocUtils {
         !simpleMenu &&
             ContextMenu.Instance.addItem({
                 description: 'Quick Notes',
-                subitems: DocListCast((Doc.UserDoc()['template-notes'] as Doc).data).map((note, i) => ({
+                subitems: DocListCast((Doc.UserDoc()['template_notes'] as Doc).data).map((note, i) => ({
                     description: ':' + StrCast(note.title),
                     event: undoable((args: { x: number; y: number }) => {
                         const textDoc = Docs.Create.TextDocument('', {
@@ -1583,10 +1578,10 @@ export namespace DocUtils {
     }
     export function findTemplate(templateName: string, type: string, signature: string) {
         let docLayoutTemplate: Opt<Doc>;
-        const iconViews = DocListCast(Cast(Doc.UserDoc()['template-icons'], Doc, null)?.data);
-        const templBtns = DocListCast(Cast(Doc.UserDoc()['template-buttons'], Doc, null)?.data);
-        const noteTypes = DocListCast(Cast(Doc.UserDoc()['template-notes'], Doc, null)?.data);
-        const clickFuncs = DocListCast(Cast(Doc.UserDoc()['template-clickFuncs'], Doc, null)?.data);
+        const iconViews = DocListCast(Cast(Doc.UserDoc()['template_icons'], Doc, null)?.data);
+        const templBtns = DocListCast(Cast(Doc.UserDoc()['template_buttons'], Doc, null)?.data);
+        const noteTypes = DocListCast(Cast(Doc.UserDoc()['template_notes'], Doc, null)?.data);
+        const clickFuncs = DocListCast(Cast(Doc.UserDoc()['template_clickFuncs'], Doc, null)?.data);
         const allTemplates = iconViews
             .concat(templBtns)
             .concat(noteTypes)
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 592f6d836..11a8dcaf6 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -97,7 +97,7 @@ export class CurrentUserUtils {
 
         const reqdOpts:DocumentOptions = {
             title: "Experimental Tools", _xMargin: 0, _layout_showTitle: "title", _chromeHidden: true,
-            _stayInCollection: true, _layout_hideContextMenu: true, _forceActive: true, isSystem: true,
+            _dragOnlyWithinContainer: true, _layout_hideContextMenu: true, _forceActive: true, isSystem: true,
             _layout_autoHeight: true, _width: 500, _height: 300, _layout_fitWidth: true, _columnWidth: 35, ignoreClick: true, _lockedPosition: true,
         };
         const reqdScripts = { dropConverter : "convertToButtons(dragData)" };
@@ -123,7 +123,7 @@ export class CurrentUserUtils {
     }
 
     /// Initializes templates for editing click funcs of a document 
-    static setupClickEditorTemplates(doc: Doc, field = "template-clickFuncs") {
+    static setupClickEditorTemplates(doc: Doc, field = "template_clickFuncs") {
         const tempClicks = DocCast(doc[field]);
         const reqdClickOpts:DocumentOptions = { _width: 300, _height:200, isSystem: true};
         const reqdTempOpts:{opts:DocumentOptions, script: string}[] = [
@@ -144,7 +144,7 @@ export class CurrentUserUtils {
     }
 
     /// Initializes templates that can be applied to notes
-    static setupNoteTemplates(doc: Doc, field="template-notes") {
+    static setupNoteTemplates(doc: Doc, field="template_notes") {
         const tempNotes = DocCast(doc[field]);
         const reqdTempOpts:DocumentOptions[] = [
             { noteType: "Note", backgroundColor: "yellow", icon: "sticky-note"},
@@ -174,7 +174,7 @@ export class CurrentUserUtils {
     }
 
     // setup templates for different document types when they are iconified from Document Decorations
-    static setupDefaultIconTemplates(doc: Doc, field="template-icons") {
+    static setupDefaultIconTemplates(doc: Doc, field="template_icons") {
         const reqdOpts = { title: "icon templates", _height: 75, isSystem: true };
         const templateIconsDoc = DocUtils.AssignOpts(DocCast(doc[field]), reqdOpts) ?? (doc[field] = Docs.Create.TreeDocument([], reqdOpts));
 
@@ -279,11 +279,11 @@ export class CurrentUserUtils {
             {key: "Script",     creator: opts => Docs.Create.ScriptingDocument(null, opts), opts: { _width: 200, _height: 250, }},
             {key: "DataViz",    creator: opts => Docs.Create.DataVizDocument("/users/rz/Downloads/addresses.csv", opts),   opts: { _width: 300, _height: 300 }},
             {key: "Header",     creator: headerTemplate,                                    opts: { _width: 300, _height: 70, _headerPointerEvents: "all", _headerHeight: 12, _headerFontSize: 9, _layout_autoHeight: true, treeViewHideUnrendered: true}},
-            {key: "Trail",      creator: Docs.Create.PresDocument,                          opts: { _width: 400, _height: 30, _type_collection: CollectionViewType.Stacking, targetDropAction: "embed" as dropActionType, treeViewHideTitle: true, _layout_fitWidth:true, _chromeHidden: true, layout_boxShadow: "0 0" }},
+            {key: "Trail",      creator: Docs.Create.PresDocument,                          opts: { _width: 400, _height: 30, _type_collection: CollectionViewType.Stacking, dropAction: "embed" as dropActionType, treeViewHideTitle: true, _layout_fitWidth:true, _chromeHidden: true, layout_boxShadow: "0 0" }},
             {key: "Tab",        creator: opts => Docs.Create.FreeformDocument([], opts),    opts: { _width: 500, _height: 800, _layout_fitWidth: true, _freeform_backgroundGrid: true, }},
             {key: "Slide",      creator: opts => Docs.Create.TreeDocument([], opts),        opts: { _width: 300, _height: 200, _type_collection: CollectionViewType.Tree, 
                                                                                                 treeViewHasOverlay: true, _text_fontSize: "20px", _layout_autoHeight: true, 
-                                                                                                allowOverlayDrop: true, treeViewType: TreeViewType.outline, 
+                                                                                                dropAction:'move', treeViewType: TreeViewType.outline, 
                                                                                                 backgroundColor: "white", _xMargin: 0, _yMargin: 0, _createDocOnCR: true 
                                                                                             }, funcs: {title: 'self.text?.Text'}},
             ];
@@ -322,17 +322,16 @@ export class CurrentUserUtils {
         const creatorBtns = CurrentUserUtils.creatorBtnDescriptors(doc).map((reqdOpts) => {
             const btn = dragCreatorDoc ? DocListCast(dragCreatorDoc.data).find(doc => doc.title === reqdOpts.title): undefined;
             const opts:DocumentOptions = {...OmitKeys(reqdOpts, ["funcs", "scripts", "backgroundColor"]).omit, 
-                _width: 35, _height: 35, _layout_hideContextMenu: true, _stayInCollection: true, 
+                _width: 35, _height: 35, _layout_hideContextMenu: true, _dragOnlyWithinContainer: true, 
                 btnType: ButtonType.ToolButton, backgroundColor: reqdOpts.backgroundColor ?? Colors.DARK_GRAY, color: Colors.WHITE, isSystem: true,
-                _removeDropProperties: new List<string>(["_stayInCollection"]),
                 };
             return DocUtils.AssignScripts(DocUtils.AssignOpts(btn, opts) ?? Docs.Create.FontIconDocument(opts), reqdOpts.scripts, reqdOpts.funcs);
         });
 
         const reqdOpts:DocumentOptions = {
-            title: "Basic Item Creators", _layout_showTitle: "title", _xMargin: 0, _stayInCollection: true, _layout_hideContextMenu: true, _chromeHidden: true, isSystem: true,
+            title: "Basic Item Creators", _layout_showTitle: "title", _xMargin: 0, _dragOnlyWithinContainer: true, _layout_hideContextMenu: true, _chromeHidden: true, isSystem: true,
             _layout_autoHeight: true, _width: 500, _height: 300, _layout_fitWidth: true, _columnWidth: 40, ignoreClick: true, _lockedPosition: true, _forceActive: true,
-             childDropAction: 'embed' 
+             childDragAction: 'embed' 
         };
         const reqdScripts = { dropConverter: "convertToButtons(dragData)" };
         return DocUtils.AssignScripts(DocUtils.AssignOpts(dragCreatorDoc, reqdOpts, creatorBtns) ?? Docs.Create.MasonryDocument(creatorBtns, reqdOpts), reqdScripts);
@@ -357,7 +356,7 @@ export class CurrentUserUtils {
 
     /// the empty panel that is filled with whichever left menu button's panel has been selected
     static setupLeftSidebarPanel(doc: Doc, field="myLeftSidebarPanel") {
-        DocUtils.AssignDocField(doc, field, (opts) => ((doc:Doc) => {doc.isSystem = true; return doc;})(new Doc()), {isSystem:true});
+        DocUtils.AssignDocField(doc, field, (opts) => Doc.assign(new Doc(), opts as any), {isSystem:true, undoIgnoreFields: new List<string>(['proto'])});
     }
 
     /// Initializes the left sidebar menu buttons and the panels they open up
@@ -367,15 +366,14 @@ export class CurrentUserUtils {
         const menuBtns = CurrentUserUtils.leftSidebarMenuBtnDescriptions(doc).map(({ title, target, icon, scripts, funcs }) => {
             const btnDoc = myLeftSidebarMenu ? DocListCast(myLeftSidebarMenu.data).find(doc => doc.title === title) : undefined;
             const reqdBtnOpts:DocumentOptions = {
-                title, icon, target, btnType: ButtonType.MenuButton, isSystem: true, dontUndo: true, dontRegisterView: true,
-                _width: 60, _height: 60,  _stayInCollection: true, _layout_hideContextMenu: true,
-                _removeDropProperties: new List<string>(["_stayInCollection"]),
+                title, icon, target, btnType: ButtonType.MenuButton, isSystem: true, undoIgnoreFields: new List<string>(['height', 'data_columnHeaders']), dontRegisterView: true,
+                _width: 60, _height: 60,  _dragOnlyWithinContainer: true, _layout_hideContextMenu: true,
             };
             return DocUtils.AssignScripts(DocUtils.AssignOpts(btnDoc, reqdBtnOpts) ?? Docs.Create.FontIconDocument(reqdBtnOpts), scripts, funcs);
         });
 
         const reqdStackOpts:DocumentOptions ={
-            title: "menuItemPanel", childDropAction: "same", backgroundColor: Colors.DARK_GRAY, layout_boxShadow: "rgba(0,0,0,0)",  dontRegisterView: true, ignoreClick: true,
+            title: "menuItemPanel", childDragAction: "same", backgroundColor: Colors.DARK_GRAY, layout_boxShadow: "rgba(0,0,0,0)",  dontRegisterView: true, ignoreClick: true,
             _chromeHidden: true, _gridGap: 0, _yMargin: 0, _yPadding: 0, _xMargin: 0, _layout_autoHeight: false, _width: 60, _columnWidth: 60, _lockedPosition: true, isSystem: true,
         };
         return DocUtils.AssignDocField(doc, field, (opts, items) => Docs.Create.StackingDocument(items??[], opts), reqdStackOpts, menuBtns, { dropConverter: "convertToButtons(dragData)" });
@@ -458,7 +456,7 @@ export class CurrentUserUtils {
     /// Search option on the left side button panel
     static setupSearcher(doc: Doc, field:string) {
         return DocUtils.AssignDocField(doc, field, (opts, items) => Docs.Create.SearchDocument(opts), {
-                dontRegisterView: true, backgroundColor: "dimgray", ignoreClick: true, title: "Search Panel", isSystem: true, childDropAction: "embed", 
+                dontRegisterView: true, backgroundColor: "dimgray", ignoreClick: true, title: "Search Panel", isSystem: true, childDragAction: "embed", 
                 _lockedPosition: true, _type_collection: CollectionViewType.Schema  });
     }
 
@@ -469,7 +467,7 @@ export class CurrentUserUtils {
         const templateBtns = CurrentUserUtils.setupExperimentalTemplateButtons(doc,DocListCast(myTools?.data)?.length > 1 ? DocListCast(myTools.data)[1]:undefined);
         const reqdToolOps:DocumentOptions = {
             title: "My Tools", isSystem: true, ignoreClick: true, layout_boxShadow: "0 0",
-            _layout_showTitle: "title", _width: 500, _yMargin: 20, _lockedPosition: true, _forceActive: true, _stayInCollection: true, _layout_hideContextMenu: true, _chromeHidden: true, 
+            _layout_showTitle: "title", _width: 500, _yMargin: 20, _lockedPosition: true, _forceActive: true, _dragOnlyWithinContainer: true, _layout_hideContextMenu: true, _chromeHidden: true, 
         };
         return DocUtils.AssignDocField(doc, field, (opts, items) => Docs.Create.StackingDocument(items??[], opts), reqdToolOps, [creatorBtns, templateBtns]);
     }
@@ -481,7 +479,7 @@ export class CurrentUserUtils {
         const toggleDarkTheme = `this.colorScheme = this.colorScheme ? undefined : "${ColorScheme.Dark}"`;
         const newDashboard = `createNewDashboard()`;
 
-        const reqdBtnOpts:DocumentOptions = { _forceActive: true,  _width: 30, _height: 30, _stayInCollection: true, _layout_hideContextMenu: true,
+        const reqdBtnOpts:DocumentOptions = { _forceActive: true,  _width: 30, _height: 30, _dragOnlyWithinContainer: true, _layout_hideContextMenu: true,
              title: "new dashboard", btnType: ButtonType.ClickButton, toolTip: "Create new dashboard", buttonText: "New trail", icon: "plus", isSystem: true };
         const reqdBtnScript = {onClick: newDashboard,}
         const newDashboardButton = DocUtils.AssignScripts(DocUtils.AssignOpts(DocCast(myDashboards?.layout_headerButton), reqdBtnOpts) ?? Docs.Create.FontIconDocument(reqdBtnOpts), reqdBtnScript);
@@ -495,8 +493,8 @@ export class CurrentUserUtils {
         const childContextMenuIcons = ["chalkboard", "tv", "camera", "users", "times", "trash"]; // entries must be kept in synch with childContextMenuScripts, childContextMenuLabels, and childContextMenuFilters
         const reqdOpts:DocumentOptions = {
             title: "My Dashboards", childHideLinkButton: true, treeViewFreezeChildren: "remove|add", treeViewHideTitle: true, layout_boxShadow: "0 0", childDontRegisterViews: true,
-            targetDropAction: "same", treeViewType: TreeViewType.fileSystem, isFolder: true, isSystem: true,  treeViewTruncateTitleWidth: 350, ignoreClick: true, 
-            layout_headerButton: newDashboardButton, childDropAction: "embed",
+            dropAction: "same", treeViewType: TreeViewType.fileSystem, isFolder: true, isSystem: true,  treeViewTruncateTitleWidth: 350, ignoreClick: true, 
+            layout_headerButton: newDashboardButton, childDragAction: "embed",
             _layout_showTitle: "title", _height: 400, _gridGap: 5, _forceActive: true, _lockedPosition: true,
             contextMenuLabels:new List<string>(contextMenuLabels),
             contextMenuIcons:new List<string>(contextMenuIcons),
@@ -520,20 +518,20 @@ export class CurrentUserUtils {
     /// initializes the left sidebar File system pane
     static setupFilesystem(doc: Doc, field:string) {
         var myFilesystem = DocCast(doc[field]);
-        const myFileOrphans = DocUtils.AssignDocField(doc, "myFileOrphans", (opts) => Docs.Create.TreeDocument([], opts), { title: "Unfiled", _stayInCollection: true, isSystem: true, isFolder: true });
+        const myFileOrphans = DocUtils.AssignDocField(doc, "myFileOrphans", (opts) => Docs.Create.TreeDocument([], opts), { title: "Unfiled", undoIgnoreFields:new List<string>(['treeViewSortCriterion']), _dragOnlyWithinContainer: true, isSystem: true, isFolder: true });
         
         const newFolder = `TreeView_addNewFolder()`;
         const newFolderOpts: DocumentOptions = {
-            _forceActive: true, _stayInCollection: true, _layout_hideContextMenu: true, _width: 30, _height: 30,
+            _forceActive: true, _dragOnlyWithinContainer: true, _layout_hideContextMenu: true, _width: 30, _height: 30, undoIgnoreFields:new List<string>(['treeViewSortCriterion']),
             title: "New folder", btnType: ButtonType.ClickButton, toolTip: "Create new folder", buttonText: "New folder", icon: "folder-plus", isSystem: true
         };
         const newFolderScript = { onClick: newFolder};
         const newFolderButton = DocUtils.AssignScripts(DocUtils.AssignOpts(DocCast(myFilesystem?.layout_headerButton), newFolderOpts) ?? Docs.Create.FontIconDocument(newFolderOpts), newFolderScript);
         
         const reqdOpts:DocumentOptions = { _layout_showTitle: "title", _height: 100, _gridGap: 5, _forceActive: true, _lockedPosition: true, 
-            title: "My Documents", layout_headerButton: newFolderButton, treeViewHideTitle: true, targetDropAction: "proto", isSystem: true,
+            title: "My Documents", layout_headerButton: newFolderButton, treeViewHideTitle: true, dropAction: "proto", isSystem: true,
             isFolder: true, treeViewType: TreeViewType.fileSystem, childHideLinkButton: true, layout_boxShadow: "0 0", childDontRegisterViews: true, 
-            treeViewTruncateTitleWidth: 350, ignoreClick: true, childDropAction: "embed",
+            treeViewTruncateTitleWidth: 350, ignoreClick: true, childDragAction: "embed",
             childContextMenuLabels: new List<string>(["Create new folder"]),
             childContextMenuIcons: new List<string>(["plus"]),
             layout_explainer: "This is your file manager where you can create folders to keep track of documents independently of your dashboard."
@@ -549,8 +547,8 @@ export class CurrentUserUtils {
     /// initializes the panel displaying docs that have been recently closed
     static setupRecentlyClosed(doc: Doc, field:string) {
         const reqdOpts:DocumentOptions = { _layout_showTitle: "title", _lockedPosition: true, _gridGap: 5, _forceActive: true, 
-            title: "My Recently Closed", childHideLinkButton: true, treeViewHideTitle: true, childDropAction: "embed", isSystem: true,
-            treeViewTruncateTitleWidth: 350, ignoreClick: true,  layout_boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same",
+            title: "My Recently Closed", childHideLinkButton: true, treeViewHideTitle: true, childDragAction: "embed", isSystem: true,
+            treeViewTruncateTitleWidth: 350, ignoreClick: true,  layout_boxShadow: "0 0", childDontRegisterViews: true, dropAction: "same",
             contextMenuLabels: new List<string>(["Empty recently closed"]),
             contextMenuIcons:new List<string>(["trash"]),
             layout_explainer: "Recently closed documents appear in this menu. They will only be deleted if you explicity empty this list."
@@ -558,7 +556,7 @@ export class CurrentUserUtils {
         const recentlyClosed = DocUtils.AssignDocField(doc, field, (opts) => Docs.Create.TreeDocument([], opts), reqdOpts);
 
         const clearAll = (target:string) => `getProto(${target}).data = new List([])`;
-        const clearBtnsOpts:DocumentOptions = { _width: 30, _height: 30, _forceActive: true, _stayInCollection: true, _layout_hideContextMenu: true, 
+        const clearBtnsOpts:DocumentOptions = { _width: 30, _height: 30, _forceActive: true, _dragOnlyWithinContainer: true, _layout_hideContextMenu: true, 
             title: "Empty", target: recentlyClosed, btnType: ButtonType.ClickButton,  buttonText: "Empty", icon: "trash", isSystem: true,
             toolTip: "Empty recently closed",};
         DocUtils.AssignDocField(recentlyClosed, "layout_headerButton", (opts) => Docs.Create.FontIconDocument(opts), clearBtnsOpts, undefined, {onClick: clearAll("self.target")});
@@ -575,7 +573,7 @@ export class CurrentUserUtils {
     static setupUserDocView(doc: Doc, field:string) {
         const reqdOpts:DocumentOptions = {
             _lockedPosition: true, _gridGap: 5, _forceActive: true, title: Doc.CurrentUserEmail +"-view",
-            layout_boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", ignoreClick: true, isSystem: true,
+            layout_boxShadow: "0 0", childDontRegisterViews: true, dropAction: "same", ignoreClick: true, isSystem: true,
             treeViewHideTitle: true, treeViewTruncateTitleWidth: 350
         };
         if (!doc[field]) DocUtils.AssignOpts(doc, {treeViewOpen: true, treeViewExpandedView: "fields" });
@@ -590,7 +588,7 @@ export class CurrentUserUtils {
 
     static createToolButton = (opts: DocumentOptions) => Docs.Create.FontIconDocument({
         btnType: ButtonType.ToolButton, _forceActive: true, _layout_hideContextMenu: true, 
-        _removeDropProperties: new List<string>([ "_layout_hideContextMenu", "stayInCollection"]), 
+        _dropPropertiesToRemove: new List<string>([ "_layout_hideContextMenu"]), 
         _nativeWidth: 40, _nativeHeight: 40, _width: 40, _height: 40, isSystem: true, ...opts,
     })
 
@@ -608,9 +606,9 @@ export class CurrentUserUtils {
             { scripts: { },                       opts: { title: "linker",            layout: "<LinkingUI>",          toolTip: "link started"}},
             { scripts: { },                       opts: { title: "currently playing", layout: "<CurrentlyPlayingUI>", toolTip: "currently playing media"}},
         ];
-        const btns = btnDescs.map(desc => dockBtn({_width: 30, _height: 30, defaultDoubleClick: 'ignore', dontUndo: true, _stayInCollection: true, ...desc.opts}, desc.scripts));
+        const btns = btnDescs.map(desc => dockBtn({_width: 30, _height: 30, defaultDoubleClick: 'ignore', undoIgnoreFields: new List<string>(['opacity']), _dragOnlyWithinContainer: true, ...desc.opts}, desc.scripts));
         const dockBtnsReqdOpts:DocumentOptions = {
-            title: "docked buttons", _height: 40, flexGap: 0, layout_boxShadow: "standard", childDropAction: 'embed',
+            title: "docked buttons", _height: 40, flexGap: 0, layout_boxShadow: "standard", childDragAction: 'move',
             childDontRegisterViews: true, linearView_IsExpanded: true, linearView_Expandable: true, ignoreClick: true
         };
         reaction(() => UndoManager.redoStack.slice(), () => Doc.GetProto(btns.find(btn => btn.title === "redo")!).opacity = UndoManager.CanRedo() ? 1 : 0.4, { fireImmediately: true });
@@ -716,12 +714,11 @@ export class CurrentUserUtils {
         const reqdOpts:DocumentOptions = {
             ...OmitKeys(params, ["scripts", "funcs", "subMenu"]).omit,
             backgroundColor: params.backgroundColor ??"transparent", ///  a bit hacky. if an onClick is specified, then assume a toggle uses onClick to get the backgroundColor (see below).  Otherwise, assume a transparent background
-            color: Colors.WHITE, isSystem: true, //dontUndo: true, 
+            color: Colors.WHITE, isSystem: true,
             _nativeWidth: params.width ?? 30, _width: params.width ?? 30,
             _height: 30, _nativeHeight: 30, linearBtnWidth: params.linearBtnWidth,
             toolType: params.toolType, expertMode: params.expertMode,
-            _stayInCollection: true, _layout_hideContextMenu: true, _lockedPosition: true,
-            _removeDropProperties: new List<string>([ "_stayInCollection"]),
+            _dragOnlyWithinContainer: true, _layout_hideContextMenu: true, _lockedPosition: true,
         };
         const reqdFuncs:{[key:string]:any} = {
             ...params.funcs,
@@ -732,14 +729,14 @@ export class CurrentUserUtils {
 
     /// Initializes all the default buttons for the top bar context menu
     static setupContextMenuButtons(doc: Doc, field="myContextMenuBtns") {
-        const reqdCtxtOpts:DocumentOptions = { title: "context menu buttons", dontUndo:true, flexGap: 0, childDropAction: 'embed', childDontRegisterViews: true,  linearView_IsExpanded: true, ignoreClick: true, linearView_Expandable: false, _height: 35 };
+        const reqdCtxtOpts:DocumentOptions = { title: "context menu buttons", undoIgnoreFields:new List<string>(['width', "linearView_IsExpanded"]), flexGap: 0, childDragAction: 'embed', childDontRegisterViews: true,  linearView_IsExpanded: true, ignoreClick: true, linearView_Expandable: false, _height: 35 };
         const ctxtMenuBtnsDoc = DocUtils.AssignDocField(doc, field, (opts, items) => this.linearButtonList(opts, items??[]), reqdCtxtOpts, undefined);
         const ctxtMenuBtns = CurrentUserUtils.contextMenuTools().map(params => {
             const menuBtnDoc = DocListCast(ctxtMenuBtnsDoc?.data).find(doc => doc.title === params.title);
             if (!params.subMenu) {
                 return this.setupContextMenuButton(params, menuBtnDoc);
             } else {
-                const reqdSubMenuOpts = { ...OmitKeys(params, ["scripts", "funcs", "subMenu"]).omit, dontUndo: true,
+                const reqdSubMenuOpts = { ...OmitKeys(params, ["scripts", "funcs", "subMenu"]).omit, undoIgnoreFields: new List<string>(['width', "linearView_IsExpanded"]),
                     childDontRegisterViews: true, flexGap: 0, _height: 30, ignoreClick: params.scripts?.onClick ? false : true,
                     linearView_SubMenu: true, linearView_Expandable: true, };
                 const items = params.subMenu?.map(sub =>
@@ -786,13 +783,13 @@ export class CurrentUserUtils {
         const sharedDocOpts:DocumentOptions = {
             title: "My Shared Docs",
             userColor: "rgb(202, 202, 202)",
-            isFolder:true,
+            isFolder:true, undoIgnoreFields:new List<string>(['treeViewSortCriterion']),
             childContextMenuFilters: new List<ScriptField>([dashboardFilter!,]),
             childContextMenuScripts: new List<ScriptField>([addToDashboards!,]),
             childContextMenuLabels: new List<string>(["Add to Dashboards",]),
             childContextMenuIcons: new List<string>(["user-plus",]),
             "acl-Public": SharingPermissions.Augment, "_acl-Public": SharingPermissions.Augment,
-            childDropAction: "embed", isSystem: true, contentPointerEvents: "all", childLimitHeight: 0, _yMargin: 0, _gridGap: 15, childDontRegisterViews:true,
+            childDragAction: "embed", isSystem: true, contentPointerEvents: "all", childLimitHeight: 0, _yMargin: 0, _gridGap: 15, childDontRegisterViews:true,
             // NOTE: treeViewHideTitle & _layout_showTitle is for a TreeView's editable title, _layout_showTitle is for DocumentViews title bar
             _layout_showTitle: "title", treeViewHideTitle: true, ignoreClick: true, _lockedPosition: true, layout_boxShadow: "0 0", _chromeHidden: true, dontRegisterView: true, 
             layout_explainer: "This is where documents or dashboards that other users have shared with you will appear. To share a document or dashboard right click and select 'Share'"
@@ -805,14 +802,14 @@ export class CurrentUserUtils {
     static setupImportSidebar(doc: Doc, field:string) {   
         const reqdOpts:DocumentOptions = {
             title: "My Imports", _forceActive: true, ignoreClick: true, _layout_showTitle: "title", 
-            _stayInCollection: true, _layout_hideContextMenu: true, childLimitHeight: 0,
-            childDropAction: "copy", _layout_autoHeight: true, _yMargin: 50, _gridGap: 15, layout_boxShadow: "0 0", _lockedPosition: true, isSystem: true, _chromeHidden: true,
+            _dragOnlyWithinContainer: true, _layout_hideContextMenu: true, childLimitHeight: 0,
+            childDragAction: "copy", _layout_autoHeight: true, _yMargin: 50, _gridGap: 15, layout_boxShadow: "0 0", _lockedPosition: true, isSystem: true, _chromeHidden: true,
             dontRegisterView: true, layout_explainer: "This is where documents that are Imported into Dash will go."
         };
         const myImports = DocUtils.AssignDocField(doc, field, (opts) => Docs.Create.StackingDocument([], opts), reqdOpts);
     
         const reqdBtnOpts:DocumentOptions = { _forceActive: true, toolTip: "Import from computer",
-            _width: 30, _height: 30, _stayInCollection: true, _layout_hideContextMenu: true, title: "Import", btnType: ButtonType.ClickButton, 
+            _width: 30, _height: 30, _dragOnlyWithinContainer: true, _layout_hideContextMenu: true, title: "Import", btnType: ButtonType.ClickButton, 
             buttonText: "Import", icon: "upload", isSystem: true };
         DocUtils.AssignDocField(myImports, "layout_headerButton", (opts) => Docs.Create.FontIconDocument(opts), reqdBtnOpts, undefined, { onClick: "importDocument()" });
         return myImports;
@@ -864,7 +861,7 @@ export class CurrentUserUtils {
         this.setupDocTemplates(doc); // sets up the template menu of templates
         this.setupFieldInfos(doc); // sets up the collection of field info descriptions for each possible DocumentOption
         DocUtils.AssignDocField(doc, "globalScriptDatabase", (opts) =>  Docs.Prototypes.MainScriptDocument(), {});
-        DocUtils.AssignDocField(doc, "myHeaderBar", (opts) => Docs.Create.MulticolumnDocument([], opts), { title: "header bar", isSystem: true }); // drop down panel at top of dashboard for stashing documents
+        DocUtils.AssignDocField(doc, "myHeaderBar", (opts) => Docs.Create.MulticolumnDocument([], opts), { title: "header bar", isSystem: true, childDocumentsActive:false, dropAction: 'move'}); // drop down panel at top of dashboard for stashing documents
         
         Doc.AddDocToList(Doc.MyFilesystem, undefined, Doc.MySharedDocs)
 
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 87833d322..85101fcab 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -15,42 +15,36 @@ import { SelectionManager } from './SelectionManager';
 import { SnappingManager } from './SnappingManager';
 import { UndoManager } from './UndoManager';
 
-export type dropActionType = 'embed' | 'copy' | 'move' | 'same' | 'proto' | 'none' | undefined; // undefined = move, "same" = move but don't call removeDropProperties
+export type dropActionType = 'embed' | 'copy' | 'move' | 'same' | 'proto' | 'none' | undefined; // undefined = move, "same" = move but don't call dropPropertiesToRemove
 
 /**
  * Initialize drag
  * @param _reference: The HTMLElement that is being dragged
  * @param docFunc: The Dash document being moved
- * @param moveFunc: The function called when the document is moved
- * @param dropAction: What to do with the document when it is dropped
- * @param dragStarted: Method to call when the drag is started
  */
-export function SetupDrag(_reference: React.RefObject<HTMLElement>, docFunc: () => Doc | Promise<Doc | undefined> | undefined, moveFunc?: DragManager.MoveFunction, dropAction?: dropActionType, dragStarted?: () => void) {
-    const onRowMove = async (e: PointerEvent) => {
+export function SetupDrag(_reference: React.RefObject<HTMLElement>, docFunc: () => Doc | undefined) {
+    const onRowMove = (e: PointerEvent) => {
         e.stopPropagation();
         e.preventDefault();
 
         document.removeEventListener('pointermove', onRowMove);
         document.removeEventListener('pointerup', onRowUp);
-        const doc = await docFunc();
+        const doc = docFunc();
         if (doc) {
             const dragData = new DragManager.DocumentDragData([doc]);
-            dragData.dropAction = dropAction;
-            dragData.moveDocument = moveFunc;
             DragManager.StartDocumentDrag([_reference.current!], dragData, e.x, e.y);
-            dragStarted?.();
         }
     };
     const onRowUp = (): void => {
         document.removeEventListener('pointermove', onRowMove);
         document.removeEventListener('pointerup', onRowUp);
     };
-    const onItemDown = async (e: React.PointerEvent) => {
+    const onItemDown = (e: React.PointerEvent) => {
         if (e.button === 0) {
             e.stopPropagation();
             if (e.shiftKey) {
                 e.persist();
-                const dragDoc = await docFunc();
+                const dragDoc = docFunc();
                 dragDoc && DragManager.StartWindowDrag?.(e, [dragDoc]);
             } else {
                 document.addEventListener('pointermove', onRowMove);
@@ -132,7 +126,7 @@ export namespace DragManager {
         userDropAction: dropActionType; // the user requested drop action -- this will be honored as specified by modifier keys
         defaultDropAction?: dropActionType; // an optionally specified default drop action when there is no user drop actionl - this will be honored if there is no user drop action
         dropAction: dropActionType; // a drop action request by the initiating code.  the actual drop action may be different -- eg, if the request is 'embed', but the document is dropped within the same collection, the drop action will be switched to 'move'
-        removeDropProperties?: string[];
+        dropPropertiesToRemove?: string[];
         moveDocument?: MoveFunction;
         removeDocument?: RemoveFunction;
         isDocDecorationMove?: boolean; // Flags that Document decorations are used to drag document which allows suppression of onDragStart scripts
@@ -189,7 +183,7 @@ export namespace DragManager {
         const handler = (e: Event) => dropFunc(e, (e as CustomEvent<DropEvent>).detail);
         const preDropHandler = (e: Event) => {
             const de = (e as CustomEvent<DropEvent>).detail;
-            (preDropFunc ?? defaultPreDropFunc)(e, de, StrCast(doc?.targetDropAction) as dropActionType);
+            (preDropFunc ?? defaultPreDropFunc)(e, de, StrCast(doc?.dropAction) as dropActionType);
         };
         element.addEventListener('dashOnDrop', handler);
         doc && element.addEventListener('dashPreDrop', preDropHandler);
@@ -230,11 +224,13 @@ export namespace DragManager {
                     )
                 ).filter(d => d);
                 !['same', 'proto'].includes(docDragData.dropAction as any) &&
-                    docDragData.droppedDocuments.forEach((drop: Doc, i: number) => {
-                        const dragProps = StrListCast(dragData.draggedDocuments[i].removeDropProperties);
-                        const remProps = (dragData?.removeDropProperties || []).concat(Array.from(dragProps));
-                        remProps.map(prop => (drop[prop] = undefined));
-                    });
+                    docDragData.droppedDocuments
+                        // .filter(drop => !drop.dragOnlyWithinContainer || ['embed', 'copy'].includes(docDragData.dropAction as any))
+                        .forEach((drop: Doc, i: number) => {
+                            const dragProps = StrListCast(dragData.draggedDocuments[i].dropPropertiesToRemove);
+                            const remProps = (dragData?.dropPropertiesToRemove || []).concat(Array.from(dragProps));
+                            [...remProps, 'dropPropertiesToRemove'].map(prop => (drop[prop] = undefined));
+                        });
             }
             return e;
         };
@@ -586,6 +582,7 @@ export namespace DragManager {
 
     async function dispatchDrag(target: Element, e: PointerEvent, complete: DragCompleteEvent, pos: { x: number; y: number }, finishDrag?: (e: DragCompleteEvent) => void, options?: DragOptions, endDrag?: () => void) {
         const dropArgs = {
+            cancelable: true, // allows preventDefault() to be called to cancel the drop
             bubbles: true,
             detail: {
                 ...pos,
@@ -598,8 +595,9 @@ export namespace DragManager {
             },
         };
         target.dispatchEvent(new CustomEvent<DropEvent>('dashPreDrop', dropArgs));
+        UndoManager.StartTempBatch(); // run drag/drop in temp batch in case drop is not allowed (so we can undo any intermediate changes)
         await finishDrag?.(complete);
-        target.dispatchEvent(new CustomEvent<DropEvent>('dashOnDrop', dropArgs));
+        UndoManager.EndTempBatch(target.dispatchEvent(new CustomEvent<DropEvent>('dashOnDrop', dropArgs))); // event return val is true unless the event preventDefault() is called
         options?.dragComplete?.(complete);
         endDrag?.();
     }
diff --git a/src/client/util/DropConverter.ts b/src/client/util/DropConverter.ts
index f46ea393a..47997cc5c 100644
--- a/src/client/util/DropConverter.ts
+++ b/src/client/util/DropConverter.ts
@@ -57,11 +57,11 @@ export function convertDropDataToButtons(data: DragManager.DocumentDragData) {
         let dbox = doc;
         // bcz: isButtonBar is intended to allow a collection of linear buttons to be dropped and nested into another collection of buttons... it's not being used yet, and isn't very elegant
         if (doc.type === DocumentType.FONTICON || StrCast(Doc.Layout(doc).layout).includes('FontIconBox')) {
-            if (data.removeDropProperties || dbox.removeDropProperties) {
+            if (data.dropPropertiesToRemove || dbox.dropPropertiesToRemove) {
                 //dbox = Doc.MakeEmbedding(doc);  // don't need to do anything if dropping an icon doc onto an icon bar since there should be no layout data for an icon
                 dbox = Doc.MakeEmbedding(dbox);
-                const dragProps = Cast(dbox.removeDropProperties, listSpec('string'), []);
-                const remProps = (data.removeDropProperties || []).concat(Array.from(dragProps));
+                const dragProps = Cast(dbox.dropPropertiesToRemove, listSpec('string'), []);
+                const remProps = (data.dropPropertiesToRemove || []).concat(Array.from(dragProps));
                 remProps.map(prop => (dbox[prop] = undefined));
             }
         } else if (!doc.onDragStart && !doc.isButtonBar) {
@@ -81,7 +81,7 @@ export function convertDropDataToButtons(data: DragManager.DocumentDragData) {
                 icon: layoutDoc.isTemplateDoc ? 'font' : 'bolt',
             });
             dbox.dragFactory = layoutDoc;
-            dbox.removeDropProperties = doc.removeDropProperties instanceof ObjectField ? ObjectField.MakeCopy(doc.removeDropProperties) : undefined;
+            dbox.dropPropertiesToRemove = doc.dropPropertiesToRemove instanceof ObjectField ? ObjectField.MakeCopy(doc.dropPropertiesToRemove) : undefined;
             dbox.onDragStart = ScriptField.MakeFunction('makeDelegate(this.dragFactory)');
         } else if (doc.isButtonBar) {
             dbox.ignoreClick = true;
diff --git a/src/client/util/UndoManager.ts b/src/client/util/UndoManager.ts
index 6fef9d660..2379cb2ab 100644
--- a/src/client/util/UndoManager.ts
+++ b/src/client/util/UndoManager.ts
@@ -91,7 +91,7 @@ export namespace UndoManager {
     let currentBatch: UndoBatch | undefined;
     export let batchCounter = observable.box(0);
     let undoing = false;
-    let tempEvents: UndoEvent[] | undefined = undefined;
+    export let tempEvents: UndoEvent[] | undefined = undefined;
 
     export function AddEvent(event: UndoEvent, value?: any): void {
         if (currentBatch && batchCounter.get() && !undoing) {
@@ -187,15 +187,11 @@ export namespace UndoManager {
         return false;
     });
 
-    export function RunInTempBatch<T>(fn: () => T) {
+    export function StartTempBatch() {
         tempEvents = [];
-        try {
-            const success = runInAction(fn);
-            if (!success) UndoManager.UndoTempBatch();
-            return success;
-        } finally {
-            tempEvents = undefined;
-        }
+    }
+    export function EndTempBatch<T>(success: boolean) {
+        UndoManager.UndoTempBatch(success);
     }
     //TODO Make this return the return value
     export function RunInBatch<T>(fn: () => T, batchName: string) {
@@ -206,10 +202,11 @@ export namespace UndoManager {
             batch.end();
         }
     }
-    export const UndoTempBatch = action(() => {
-        if (tempEvents) {
+    export const UndoTempBatch = action((success: any) => {
+        if (tempEvents && !success) {
             undoing = true;
             for (let i = tempEvents.length - 1; i >= 0; i--) {
+                currentBatch?.includes(tempEvents[i]) && currentBatch.splice(currentBatch.indexOf(tempEvents[i]));
                 tempEvents[i].undo();
             }
             undoing = false;
diff --git a/src/client/views/DashboardView.tsx b/src/client/views/DashboardView.tsx
index 50cf2226e..6aae302ac 100644
--- a/src/client/views/DashboardView.tsx
+++ b/src/client/views/DashboardView.tsx
@@ -389,7 +389,7 @@ export class DashboardView extends React.Component {
             _forceActive: true,
             _width: 30,
             _height: 30,
-            _stayInCollection: true,
+            _dragOnlyWithinContainer: true,
             _layout_hideContextMenu: true,
             title: 'New trail',
             toolTip: 'Create new trail',
@@ -412,7 +412,7 @@ export class DashboardView extends React.Component {
             _layout_fitWidth: true,
             _gridGap: 5,
             _forceActive: true,
-            childDropAction: 'embed',
+            childDragAction: 'embed',
             treeViewTruncateTitleWidth: 150,
             ignoreClick: true,
             layout_headerButton: myTrailsBtn,
@@ -421,7 +421,7 @@ export class DashboardView extends React.Component {
             _lockedPosition: true,
             layout_boxShadow: '0 0',
             childDontRegisterViews: true,
-            targetDropAction: 'same',
+            dropAction: 'same',
             isSystem: true,
             layout_explainer: 'All of the trails that you have created will appear here.',
         };
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index db24229dc..0709d6cb9 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -172,8 +172,8 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps>()
                 return true;
             }
             const first = doc instanceof Doc ? doc : doc[0];
-            if (!first?._stayInCollection && addDocument !== returnFalse) {
-                return UndoManager.RunInTempBatch(() => this.removeDocument(doc, annotationKey, true) && addDocument(doc, annotationKey));
+            if (!first?._dragOnlyWithinContainer && addDocument !== returnFalse) {
+                return this.removeDocument(doc, annotationKey, true) && addDocument(doc, annotationKey);
             }
             return false;
         };
@@ -213,7 +213,7 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps>()
                         .map(doc => {
                             // only make a pushpin if we have acl's to edit the document
                             //DocUtils.LeavePushpin(doc);
-                            doc._stayInCollection = undefined;
+                            doc._dragOnlyWithinContainer = undefined;
                             doc.embedContainer = this.props.Document;
                             if (annotationKey ?? this._annotationKeySuffix()) Doc.GetProto(doc).annotationOn = this.rootDoc;
 
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 528b82e3e..41ce08d3c 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -603,7 +603,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
                     let actualdH = Math.max(docheight + dH * scale, 20);
                     let dX = !dWin ? 0 : scale * refCent[0] * (1 - (1 + dWin / refWidth));
                     let dY = !dHin ? 0 : scale * refCent[1] * (1 - (1 + dHin / refHeight));
-                    const preserveNativeDim = doc._nativeHeightUnfrozen === false && doc._nativeDimModifiable === false;
+                    const preserveNativeDim = !doc._nativeHeightUnfrozen && !doc._nativeDimModifiable;
                     const fixedAspect = nwidth && nheight && (!doc._layout_fitWidth || preserveNativeDim || e.ctrlKey || doc.nativeHeightUnfrozen || doc.nativeDimModifiable);
                     if (fixedAspect) {
                         if ((Math.abs(dW) > Math.abs(dH) && ((!dragBottom && !dragTop) || !modifyNativeDim)) || dragRight) {
@@ -636,7 +636,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
                                 }
                             }
                             if (!modifyNativeDim) {
-                                actualdH = (nheight / nwidth) * docwidth; //, actualdH);
+                                actualdH = (nheight / nwidth) * NumCast(doc._width); //, actualdH);
                             }
                             doc._height = actualdH;
                         }
@@ -756,7 +756,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
             hideDecorations ||
             seldocview.props.hideOpenButton ||
             seldocview.rootDoc.layout_hideOpenButton ||
-            SelectionManager.Views().some(docView => docView.rootDoc._stayInCollection || docView.rootDoc.isGroup || docView.rootDoc.layout_hideOpenButton) ||
+            SelectionManager.Views().some(docView => docView.rootDoc._dragOnlyWithinContainer || docView.rootDoc.isGroup || docView.rootDoc.layout_hideOpenButton) ||
             this._isRounding ||
             this._isRotating;
         const hideDeleteButton =
@@ -767,7 +767,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
             seldocview.rootDoc.hideDeleteButton ||
             SelectionManager.Views().some(docView => {
                 const collectionAcl = docView.props.docViewPath()?.lastElement() ? GetEffectiveAcl(docView.props.docViewPath().lastElement().rootDoc[DocData]) : AclEdit;
-                return (docView.rootDoc.stayInCollection && !docView.rootDoc._isTimelineLabel) || (collectionAcl !== AclAdmin && collectionAcl !== AclEdit && GetEffectiveAcl(docView.rootDoc) !== AclAdmin);
+                return collectionAcl !== AclAdmin && collectionAcl !== AclEdit && GetEffectiveAcl(docView.rootDoc) !== AclAdmin;
             });
 
         const topBtn = (key: string, icon: string, pointerDown: undefined | ((e: React.PointerEvent) => void), click: undefined | ((e: any) => void), title: string) => (
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index 0951bff22..54ad519de 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -4,8 +4,7 @@ import { action, computed, observable, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
 import { Doc, Opt } from '../../fields/Doc';
 import { InkData, InkTool } from '../../fields/InkField';
-import { ScriptField } from '../../fields/ScriptField';
-import { Cast, FieldValue, NumCast } from '../../fields/Types';
+import { NumCast } from '../../fields/Types';
 import MobileInkOverlay from '../../mobile/MobileInkOverlay';
 import { GestureUtils } from '../../pen-gestures/GestureUtils';
 import { MobileInkOverlayContent } from '../../server/Message';
@@ -35,7 +34,6 @@ import { InkTranscription } from './InkTranscription';
 import { checkInksToGroup } from './nodes/button/FontIconBox';
 import { DocumentView } from './nodes/DocumentView';
 import { RadialMenu } from './nodes/RadialMenu';
-import HorizontalPalette from './Palette';
 import { Touchable } from './Touchable';
 import TouchScrollableMenu, { TouchScrollableMenuItem } from './TouchScrollableMenu';
 
@@ -79,7 +77,6 @@ export class GestureOverlay extends Touchable<GestureOverlayProps> {
     private _overlayRef = React.createRef<HTMLDivElement>();
     private _d1: Doc | undefined;
     private _inkToTextDoc: Doc | undefined;
-    private _thumbDoc: Doc | undefined;
     private thumbIdentifier?: number;
     private pointerIdentifier?: number;
     private _hands: Map<number, React.Touch[]> = new Map<number, React.Touch[]>();
@@ -93,78 +90,12 @@ export class GestureOverlay extends Touchable<GestureOverlayProps> {
         GestureOverlay.Instances.push(this);
     }
 
-    static setupThumbButtons(doc: Doc) {
-        const docProtoData: { title: string; icon: string; drag?: string; toolType?: string; ignoreClick?: boolean; pointerDown?: string; pointerUp?: string; clipboard?: Doc; backgroundColor?: string; dragFactory?: Doc }[] = [
-            { title: 'use pen', icon: 'pen-nib', pointerUp: 'resetPen()', pointerDown: 'setPen(2, this.backgroundColor)', backgroundColor: 'blue' },
-            { title: 'use highlighter', icon: 'highlighter', pointerUp: 'resetPen()', pointerDown: 'setPen(20, this.backgroundColor)', backgroundColor: 'yellow' },
-            {
-                title: 'notepad',
-                icon: 'clipboard',
-                pointerUp: 'GestureOverlay.Instance.closeFloatingDoc()',
-                pointerDown: 'GestureOverlay.Instance.openFloatingDoc(this.clipboard)',
-                clipboard: Docs.Create.FreeformDocument([], { _width: 300, _height: 300, isSystem: true }),
-                backgroundColor: 'orange',
-            },
-            { title: 'interpret text', icon: 'font', toolType: 'inktotext', pointerUp: "setToolglass('none')", pointerDown: 'setToolglass(self.toolType)', backgroundColor: 'orange' },
-            { title: 'ignore gestures', icon: 'signature', toolType: 'ignoregesture', pointerUp: "setToolglass('none')", pointerDown: 'setToolglass(self.toolType)', backgroundColor: 'green' },
-        ];
-        return docProtoData.map(data =>
-            Docs.Create.FontIconDocument({
-                _nativeWidth: 10,
-                _nativeHeight: 10,
-                _width: 10,
-                _height: 10,
-                title: data.title,
-                icon: data.icon,
-                toolType: data.toolType,
-                _dropAction: data.pointerDown ? 'copy' : undefined,
-                ignoreClick: data.ignoreClick,
-                onDragStart: data.drag ? ScriptField.MakeFunction(data.drag) : undefined,
-                clipboard: data.clipboard,
-                onPointerUp: data.pointerUp ? ScriptField.MakeScript(data.pointerUp) : undefined,
-                onPointerDown: data.pointerDown ? ScriptField.MakeScript(data.pointerDown) : undefined,
-                backgroundColor: data.backgroundColor,
-                dragFactory: data.dragFactory,
-                isSystem: true,
-            })
-        );
-    }
-
-    static setupThumbDoc(userDoc: Doc) {
-        if (!userDoc.thumbDoc) {
-            const thumbDoc = Docs.Create.LinearDocument(GestureOverlay.setupThumbButtons(userDoc), {
-                _width: 100,
-                _height: 50,
-                ignoreClick: true,
-                _lockedPosition: true,
-                title: 'buttons',
-                _layout_autoHeight: true,
-                _yMargin: 5,
-                linearView_IsExpanded: true,
-                backgroundColor: 'white',
-                isSystem: true,
-            });
-            thumbDoc.inkToTextDoc = Docs.Create.LinearDocument([], {
-                _width: 300,
-                _height: 25,
-                _layout_autoHeight: true,
-                linearView_IsExpanded: true,
-                flexDirection: 'column',
-                isSystem: true,
-            });
-            userDoc.thumbDoc = thumbDoc;
-        }
-        return Cast(userDoc.thumbDoc, Doc);
-    }
-
     componentWillUnmount() {
         GestureOverlay.Instances.splice(GestureOverlay.Instances.indexOf(this), 1);
         GestureOverlay.Instance = GestureOverlay.Instances.lastElement();
     }
     componentDidMount = () => {
         GestureOverlay.Instance = this;
-        this._thumbDoc = FieldValue(Cast(GestureOverlay.setupThumbDoc(Doc.UserDoc()), Doc));
-        this._inkToTextDoc = FieldValue(Cast(this._thumbDoc?.inkToTextDoc, Doc));
     };
 
     // TODO: nda - add dragging groups with one finger drag and have to click into group to scroll within the group
@@ -395,24 +326,6 @@ export class GestureOverlay extends Touchable<GestureOverlayProps> {
 
         this.thumbIdentifier = thumb?.identifier;
         this._hands.set(thumb.identifier, fingers);
-        const others = fingers.filter(f => f !== thumb);
-        const minX = Math.min(...others.map(f => f.clientX));
-        const minY = Math.min(...others.map(f => f.clientY));
-
-        // load up the palette collection around the thumb
-        const thumbDoc = await Cast(GestureOverlay.setupThumbDoc(Doc.UserDoc()), Doc);
-        if (thumbDoc) {
-            runInAction(() => {
-                RadialMenu.Instance._display = false;
-                this._inkToTextDoc = FieldValue(Cast(thumbDoc.inkToTextDoc, Doc));
-                this._thumbDoc = thumbDoc;
-                this._thumbX = thumb.clientX;
-                this._thumbY = thumb.clientY;
-                this._menuX = thumb.clientX + 50;
-                this._menuY = thumb.clientY;
-                this._palette = <HorizontalPalette key="palette" x={minX} y={minY} thumb={[thumb.clientX, thumb.clientY]} thumbDoc={thumbDoc} />;
-            });
-        }
 
         this.removeMoveListeners();
         document.removeEventListener('touchmove', this.handleHandMove);
@@ -462,11 +375,6 @@ export class GestureOverlay extends Touchable<GestureOverlayProps> {
                         if (Math.abs(pt.clientY - this._thumbY) > 10 * window.devicePixelRatio) {
                             this._selectedIndex = Math.min(Math.max(-1, -Math.ceil((pt.clientY - this._thumbY) / (10 * window.devicePixelRatio)) - 1), this._possibilities.length - 1);
                         }
-                    } else if (this._thumbDoc) {
-                        if (Math.abs(pt.clientX - this._thumbX) > 15 * window.devicePixelRatio) {
-                            this._thumbDoc.selectedIndex = Math.max(-1, NumCast(this._thumbDoc.selectedIndex) - Math.sign(pt.clientX - this._thumbX));
-                            this._thumbX = pt.clientX;
-                        }
                     }
                 }
             }
@@ -485,7 +393,6 @@ export class GestureOverlay extends Touchable<GestureOverlayProps> {
             if (this.thumbIdentifier) this._hands.delete(this.thumbIdentifier);
             this._palette = undefined;
             this.thumbIdentifier = undefined;
-            this._thumbDoc = undefined;
 
             // this chunk of code is for handling the ink to text toolglass
             let scriptWorked = false;
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 1a9d15c1a..dbe8fb608 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -30,6 +30,7 @@ import { ColorScheme, SettingsManager } from '../util/SettingsManager';
 import { SharingManager } from '../util/SharingManager';
 import { SnappingManager } from '../util/SnappingManager';
 import { Transform } from '../util/Transform';
+import { UndoManager } from '../util/UndoManager';
 import { TimelineMenu } from './animationtimeline/TimelineMenu';
 import { CollectionDockingView } from './collections/CollectionDockingView';
 import { MarqueeOptionsMenu } from './collections/collectionFreeForm/MarqueeOptionsMenu';
@@ -571,7 +572,7 @@ export class MainView extends React.Component {
 
     @action
     createNewFolder = async () => {
-        const folder = Docs.Create.TreeDocument([], { title: 'Untitled folder', _stayInCollection: true, isFolder: true });
+        const folder = Docs.Create.TreeDocument([], { title: 'Untitled folder', _dragOnlyWithinContainer: true, isFolder: true });
         Doc.AddDocToList(Doc.MyFilesystem, 'data', folder);
     };
 
@@ -582,6 +583,8 @@ export class MainView extends React.Component {
     waitForDoubleClick = () => (this._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);
+    removeHeaderDoc = (doc: Doc | Doc[], annotationKey?: string) => (doc instanceof Doc ? [doc] : doc).reduce((done, doc) => Doc.RemoveDocFromList(this.headerBarDoc, 'data', doc), true);
     @computed get headerBarDocView() {
         return (
             <div className="mainView-headerBar" style={{ height: this.headerBarDocHeight() }}>
@@ -589,18 +592,19 @@ export class MainView extends React.Component {
                     key="headerBarDoc"
                     Document={this.headerBarDoc}
                     DataDoc={undefined}
-                    addDocument={undefined}
                     addDocTab={DocumentViewInternal.addDocTabFunc}
                     pinToPres={emptyFunction}
                     docViewPath={returnEmptyDoclist}
                     styleProvider={DefaultStyleProvider}
                     rootSelected={returnTrue}
-                    removeDocument={returnFalse}
+                    addDocument={this.addHeaderDoc}
+                    removeDocument={this.removeHeaderDoc}
                     fitContentsToBox={returnTrue}
                     isDocumentActive={returnTrue} // headerBar is always documentActive (ie, the docView gets pointer events)
                     isContentActive={returnTrue} // headerBar is awlays contentActive which means its items are always documentActive
                     ScreenToLocalTransform={this.headerBarScreenXf}
                     childHideResizeHandles={returnTrue}
+                    childDragAction="move"
                     dontRegisterView={true}
                     hideResizeHandles={true}
                     PanelWidth={this.headerBarDocWidth}
@@ -865,7 +869,7 @@ export class MainView extends React.Component {
         this._leftMenuFlyoutWidth = 0;
     });
 
-    remButtonDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((flg: boolean, doc) => flg && Doc.RemoveDocFromList(Doc.MyDockedBtns, 'data', doc), true);
+    remButtonDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((flg: boolean, doc) => flg && !doc.dragOnlyWithinContainer && Doc.RemoveDocFromList(Doc.MyDockedBtns, 'data', doc), true);
     moveButtonDoc = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => this.remButtonDoc(doc) && addDocument(doc);
     addButtonDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((flg: boolean, doc) => flg && Doc.AddDocToList(Doc.MyDockedBtns, 'data', doc), true);
 
diff --git a/src/client/views/Palette.scss b/src/client/views/Palette.scss
deleted file mode 100644
index 0ec879288..000000000
--- a/src/client/views/Palette.scss
+++ /dev/null
@@ -1,30 +0,0 @@
-.palette-container {
-    .palette-thumb {
-        touch-action: pan-x;
-        position: absolute;
-        height: 70px;
-        overflow: hidden;
-
-        .palette-thumbContent {
-            transition: transform .3s;
-            width: max-content;
-            overflow: hidden;
-
-            .collectionView {
-                overflow: visible;
-
-                .collectionLinearView-outer {
-                    overflow: visible;
-                }
-            }
-        }
-
-        .palette-cover {
-            width: 50px;
-            height: 50px;
-            position: absolute;
-            bottom: 0;
-            border: 1px solid black;
-        }
-    }
-}
\ No newline at end of file
diff --git a/src/client/views/Palette.tsx b/src/client/views/Palette.tsx
deleted file mode 100644
index 749eb08a2..000000000
--- a/src/client/views/Palette.tsx
+++ /dev/null
@@ -1,69 +0,0 @@
-import { IReactionDisposer, observable, reaction } from 'mobx';
-import { observer } from 'mobx-react';
-import * as React from 'react';
-import { Doc } from '../../fields/Doc';
-import { NumCast } from '../../fields/Types';
-import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, emptyPath } from '../../Utils';
-import { Transform } from '../util/Transform';
-import { DocumentView } from './nodes/DocumentView';
-import './Palette.scss';
-
-export interface PaletteProps {
-    x: number;
-    y: number;
-    thumb: number[];
-    thumbDoc: Doc;
-}
-
-@observer
-export default class Palette extends React.Component<PaletteProps> {
-    private _selectedDisposer?: IReactionDisposer;
-    @observable private _selectedIndex: number = 0;
-
-    componentDidMount = () => {
-        this._selectedDisposer = reaction(
-            () => NumCast(this.props.thumbDoc.selectedIndex),
-            i => (this._selectedIndex = i),
-            { fireImmediately: true }
-        );
-    };
-
-    componentWillUnmount = () => {
-        this._selectedDisposer?.();
-    };
-
-    render() {
-        return (
-            <div className="palette-container" style={{ transform: `translate(${this.props.x}px, ${this.props.y}px)` }}>
-                <div className="palette-thumb" style={{ transform: `translate(${this.props.thumb[0] - this.props.x}px, ${this.props.thumb[1] - this.props.y}px)` }}>
-                    <div className="palette-thumbContent" style={{ transform: `translate(-${this._selectedIndex * 50 + 10}px, 0px)` }}>
-                        <DocumentView
-                            Document={this.props.thumbDoc}
-                            DataDoc={undefined}
-                            addDocument={undefined}
-                            addDocTab={returnFalse}
-                            rootSelected={returnTrue}
-                            pinToPres={emptyFunction}
-                            removeDocument={undefined}
-                            ScreenToLocalTransform={Transform.Identity}
-                            PanelWidth={() => window.screen.width}
-                            PanelHeight={() => window.screen.height}
-                            renderDepth={0}
-                            isDocumentActive={returnTrue}
-                            isContentActive={emptyFunction}
-                            focus={emptyFunction}
-                            docViewPath={returnEmptyDoclist}
-                            styleProvider={returnEmptyString}
-                            whenChildContentsActiveChanged={emptyFunction}
-                            bringToFront={emptyFunction}
-                            childFilters={returnEmptyFilter}
-                            childFiltersByRanges={returnEmptyFilter}
-                            searchFilterDocs={returnEmptyDoclist}
-                        />
-                        <div className="palette-cover" style={{ transform: `translate(${Math.max(0, this._selectedIndex) * 50.75 + 23}px, 0px)` }}></div>
-                    </div>
-                </div>
-            </div>
-        );
-    }
-}
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 1f2e21dd5..09aac053a 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -287,7 +287,6 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                         pinToPres={emptyFunction}
                         bringToFront={returnFalse}
                         dontRegisterView={true}
-                        dropAction={undefined}
                     />
                 </div>
             );
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index 2cca2c5a9..330ccc583 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -265,6 +265,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
         }
         case StyleProp.PointerEvents:
             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 (props?.contentPointerEvents) return StrCast(props.contentPointerEvents);
diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx
index 62f47ba71..5c2ab3f70 100644
--- a/src/client/views/TemplateMenu.tsx
+++ b/src/client/views/TemplateMenu.tsx
@@ -97,8 +97,8 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
         TraceMobx();
         const firstDoc = this.props.docViews[0].props.Document;
         const templateName = StrCast(firstDoc.layout_fieldKey, 'layout').replace('layout_', '');
-        const noteTypes = DocListCast(Cast(Doc.UserDoc()['template-notes'], Doc, null)?.data);
-        const addedTypes = DocListCast(Cast(Doc.UserDoc()['template-clickFuncs'], Doc, null)?.data);
+        const noteTypes = DocListCast(Cast(Doc.UserDoc()['template_notes'], Doc, null)?.data);
+        const addedTypes = DocListCast(Cast(Doc.UserDoc()['template_clickFuncs'], Doc, null)?.data);
         const templateMenu: Array<JSX.Element> = [];
         this.props.templates?.forEach((checked, template) => templateMenu.push(<TemplateToggle key={template} template={template} checked={checked} toggle={this.toggleTemplate} />));
         templateMenu.push(<OtherToggle key={'default'} name={'Default'} checked={templateName === 'layout'} toggle={this.toggleDefault} />);
@@ -122,7 +122,6 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
                     rootSelected={returnFalse}
                     onCheckedClick={this.scriptField}
                     onChildClick={this.scriptField}
-                    dropAction={undefined}
                     isAnyChildContentActive={returnFalse}
                     isContentActive={returnTrue}
                     bringToFront={emptyFunction}
diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx
index 0eb61a0b2..ea02bcd4c 100644
--- a/src/client/views/collections/CollectionCarouselView.tsx
+++ b/src/client/views/collections/CollectionCarouselView.tsx
@@ -4,7 +4,7 @@ import { observer } from 'mobx-react';
 import * as React from 'react';
 import { Doc, Opt } from '../../../fields/Doc';
 import { NumCast, ScriptCast, StrCast } from '../../../fields/Types';
-import { returnFalse, returnZero, StopEvent } from '../../../Utils';
+import { emptyFunction, returnFalse, returnZero, StopEvent } from '../../../Utils';
 import { DragManager } from '../../util/DragManager';
 import { DocumentView, DocumentViewProps } from '../nodes/DocumentView';
 import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox';
@@ -60,6 +60,8 @@ export class CollectionCarouselView extends CollectionSubView() {
                         NativeHeight={returnZero}
                         onDoubleClick={this.onContentDoubleClick}
                         onClick={this.onContentClick}
+                        isDocumentActive={this.props.childDocumentsActive?.() ? this.props.isDocumentActive : this.props.isContentActive}
+                        isContentActive={this.props.childContentsActive ?? this.props.isContentActive() === false ? returnFalse : emptyFunction}
                         hideCaptions={show_captions ? true : false}
                         renderDepth={this.props.renderDepth + 1}
                         LayoutTemplate={this.props.childLayoutTemplate}
diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx
index 675f23970..9a3ab8074 100644
--- a/src/client/views/collections/CollectionNoteTakingView.tsx
+++ b/src/client/views/collections/CollectionNoteTakingView.tsx
@@ -10,7 +10,7 @@ import { listSpec } from '../../../fields/Schema';
 import { SchemaHeaderField } from '../../../fields/SchemaHeaderField';
 import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
 import { TraceMobx } from '../../../fields/util';
-import { emptyFunction, returnEmptyDoclist, returnFalse, returnTrue, returnZero, smoothScroll, Utils } from '../../../Utils';
+import { emptyFunction, returnFalse, returnZero, smoothScroll, Utils } from '../../../Utils';
 import { Docs, DocUtils } from '../../documents/Documents';
 import { DragManager, dropActionType } from '../../util/DragManager';
 import { SnappingManager } from '../../util/SnappingManager';
@@ -250,7 +250,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
                 dontRegisterView={dataDoc ? true : BoolCast(this.layoutDoc.childDontRegisterViews, this.props.dontRegisterView)}
                 rootSelected={this.rootSelected}
                 layout_showTitle={this.props.childlayout_showTitle}
-                dropAction={StrCast(this.layoutDoc.childDropAction) as dropActionType}
+                dragAction={StrCast(this.layoutDoc.childDragAction) as dropActionType}
                 onClick={this.onChildClickHandler}
                 onDoubleClick={this.onChildDoubleClickHandler}
                 ScreenToLocalTransform={noteTakingDocTransform}
@@ -619,7 +619,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
     }
 
     @computed get backgroundEvents() {
-        return SnappingManager.GetIsDragging();
+        return this.props.isContentActive() === false ? 'none' : undefined;
     }
 
     observer: any;
diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx
index 57d9bbb49..15570b195 100644
--- a/src/client/views/collections/CollectionPileView.tsx
+++ b/src/client/views/collections/CollectionPileView.tsx
@@ -52,18 +52,21 @@ export class CollectionPileView extends CollectionSubView() {
     @computed get toggleIcon() {
         return ScriptField.MakeScript('documentView.iconify()', { documentView: 'any' });
     }
+    @computed get contentEvents() {
+        const isStarburst = this.layoutEngine() === computeStarburstLayout.name;
+        return this.props.isContentActive() && isStarburst ? undefined : 'none';
+    }
 
     // returns the contents of the pileup in a CollectionFreeFormView
     @computed get contents() {
-        const isStarburst = this.layoutEngine() === computeStarburstLayout.name;
         return (
-            <div className="collectionPileView-innards" style={{ pointerEvents: isStarburst || SnappingManager.GetIsDragging() ? undefined : 'none' }}>
+            <div className="collectionPileView-innards" style={{ pointerEvents: this.contentEvents }}>
                 <CollectionFreeFormView
-                    {...this.props}
+                    {...this.props} //
                     childContentsActive={returnFalse}
                     layoutEngine={this.layoutEngine}
                     addDocument={this.addPileDoc}
-                    childCanEmbedOnDrag={true}
+                    childDragAction="move"
                     childClickScript={this.toggleIcon}
                     moveDocument={this.removePileDoc}
                 />
diff --git a/src/client/views/collections/CollectionStackedTimeline.scss b/src/client/views/collections/CollectionStackedTimeline.scss
index a55b70e22..a19d8e696 100644
--- a/src/client/views/collections/CollectionStackedTimeline.scss
+++ b/src/client/views/collections/CollectionStackedTimeline.scss
@@ -104,7 +104,7 @@
 
         .collectionStackedTimeline-left-resizer,
         .collectionStackedTimeline-resizer {
-            background: $medium-gray;
+            background: $dark-gray;
             position: absolute;
             top: 0;
             height: 100%;
diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index 9d5cb257a..e835fa659 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -119,8 +119,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
         // onClick play scripts
         CollectionStackedTimeline.RangeScript =
             CollectionStackedTimeline.RangeScript ||
-            ScriptField.MakeFunction(`setTimeout(() => scriptContext.clickAnchor(this, clientX))`, {
-                // setTimeout is a hack to run script in its own properly named undo group (instead of being part of the generic onClick)
+            ScriptField.MakeFunction(`scriptContext.clickAnchor(this, clientX)`, {
                 self: Doc.name,
                 scriptContext: 'any',
                 clientX: 'number',
@@ -406,7 +405,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
                 title: ComputedField.MakeFunction(`self["${endTag}"] ? "#" + formatToTime(self["${startTag}"]) + "-" + formatToTime(self["${endTag}"]) : "#" + formatToTime(self["${startTag}"])`) as any,
                 _label_minFontSize: 12,
                 _label_maxFontSize: 24,
-                _stayInCollection: true,
+                _dragOnlyWithinContainer: true,
                 backgroundColor: 'rgba(128, 128, 128, 0.5)',
                 layout_hideLinkButton: true,
                 onClick: FollowLinkScript(),
@@ -528,6 +527,9 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
         );
     }
 
+    @computed get timelineEvents() {
+        return this.props.isContentActive() ? 'all' : this.props.isContentActive() === false ? 'none' : undefined;
+    }
     render() {
         const overlaps: {
             anchorStartTime: number;
@@ -540,7 +542,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
         }));
         const maxLevel = overlaps.reduce((m, o) => Math.max(m, o.level), 0) + 2;
         return this.clipDuration === 0 ? null : (
-            <div ref={this.createDashEventsTarget} style={{ pointerEvents: SnappingManager.GetIsDragging() ? 'all' : undefined }}>
+            <div ref={this.createDashEventsTarget} style={{ pointerEvents: this.timelineEvents }}>
                 <div
                     className="collectionStackedTimeline-timelineContainer"
                     style={{ width: this.props.PanelWidth(), cursor: SnappingManager.GetIsDragging() ? 'grab' : '' }}
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 3c0d8cbc3..8eed4f716 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -17,7 +17,7 @@ import { CollectionViewType } from '../../documents/DocumentTypes';
 import { DragManager, dropActionType } from '../../util/DragManager';
 import { SnappingManager } from '../../util/SnappingManager';
 import { Transform } from '../../util/Transform';
-import { undoBatch } from '../../util/UndoManager';
+import { undoBatch, UndoManager } from '../../util/UndoManager';
 import { ContextMenu } from '../ContextMenu';
 import { ContextMenuProps } from '../ContextMenuItem';
 import { EditableView } from '../EditableView';
@@ -295,7 +295,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
             return this.addDocument?.(newDoc);
         }
     };
-    isContentActive = () => (this.props.isSelected() || this.props.isContentActive() ? true : this.props.isSelected() === false || this.props.isContentActive() === false ? false : undefined);
+    isContentActive = () => (this.props.isContentActive() ? true : this.props.isSelected() === false || this.props.isContentActive() === false ? false : undefined);
 
     @observable _renderCount = 5;
     isChildContentActive = () =>
@@ -341,7 +341,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
                 dontRegisterView={BoolCast(this.layoutDoc.childDontRegisterViews, this.props.dontRegisterView)} // used to be true if DataDoc existed, but template textboxes won't layout_autoHeight resize if dontRegisterView is set, but they need to.
                 rootSelected={this.rootSelected}
                 layout_showTitle={this.props.childlayout_showTitle}
-                dropAction={StrCast(this.layoutDoc.childDropAction) as dropActionType}
+                dragAction={(this.layoutDoc.childDragAction ?? this.props.childDragAction) as dropActionType}
                 onClick={this.onChildClickHandler}
                 onDoubleClick={this.onChildDoubleClickHandler}
                 ScreenToLocalTransform={stackedDocTransform}
@@ -402,11 +402,15 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
     // This following three functions must be from the view Mehek showed
     columnDividerDown = (e: React.PointerEvent) => {
         runInAction(() => (this._cursor = 'grabbing'));
+        const batch = UndoManager.StartBatch('stacking width');
         setupMoveUpEvents(
             this,
             e,
             this.onDividerMove,
-            action(() => (this._cursor = 'grab')),
+            action(() => {
+                this._cursor = 'grab';
+                batch.end();
+            }),
             emptyFunction
         );
     };
@@ -700,7 +704,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
     }
 
     @computed get backgroundEvents() {
-        return SnappingManager.GetIsDragging();
+        return this.props.isContentActive() === false ? 'none' : undefined;
     }
     observer: any;
     render() {
@@ -710,7 +714,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
             SetValue: this.addGroup,
             contents: '+ ADD A GROUP',
         };
-        const buttonMenu = this.rootDoc.buttonMenu;
+        const buttonMenu = this.rootDoc.layout_headerButton;
         const noviceExplainer = this.rootDoc.layout_explainer;
         return (
             <>
@@ -727,7 +731,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
                         style={{
                             overflowY: this.isContentActive() ? 'auto' : 'hidden',
                             background: this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor),
-                            pointerEvents: (this.props.pointerEvents?.() as any) ?? (this.backgroundEvents ? 'all' : undefined),
+                            pointerEvents: (this.props.pointerEvents?.() as any) ?? this.backgroundEvents,
                         }}
                         onScroll={action(e => (this._scroll = e.currentTarget.scrollTop))}
                         onDrop={this.onExternalDrop.bind(this)}
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index d1b7f6ff6..539dde7e0 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -187,7 +187,7 @@ export function CollectionSubView<X>(moreProps?: X) {
 
         protected onInternalPreDrop(e: Event, de: DragManager.DropEvent, targetAction: dropActionType) {
             if (de.complete.docDragData) {
-                // if targetDropAction is, say 'embed', but we're just dragging within a collection, we want to ignore the targetAction.
+                // if dropAction is, say 'embed', but we're just dragging within a collection, we want to ignore the targetAction.
                 // otherwise, the targetAction should become the actual action (which can still be overridden by the userDropAction -eg, shift/ctrl keys)
                 if (targetAction && !de.complete.docDragData.draggedDocuments.some(d => d.embedContainer === this.props.Document && this.childDocs.includes(d))) {
                     de.complete.docDragData.dropAction = targetAction;
@@ -212,16 +212,16 @@ export function CollectionSubView<X>(moreProps?: X) {
                     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 = this.props.Document._type_collection === CollectionViewType.Pile || de.embedKey || this.props.Document.allowOverlayDrop || Doc.AreProtosEqual(Cast(movedDocs[0].annotationOn, Doc, null), this.props.Document);
-                        added = docDragData.moveDocument(movedDocs, this.props.Document, canAdd ? this.addDocument : returnFalse);
+                        const canAdd = de.embedKey || dropAction || Doc.AreProtosEqual(Cast(movedDocs[0].annotationOn, Doc, null), this.rootDoc);
+                        added = docDragData.moveDocument(movedDocs, this.rootDoc, canAdd ? this.addDocument : returnFalse);
                     } else {
-                        ScriptCast(this.props.Document.dropConverter)?.script.run({ dragData: docDragData });
+                        ScriptCast(this.rootDoc.dropConverter)?.script.run({ dragData: docDragData });
                         added = addedDocs.length ? this.addDocument(addedDocs) : true;
                     }
                     added && e.stopPropagation();
                     return added;
                 } else {
-                    ScriptCast(this.props.Document.dropConverter)?.script.run({ dragData: docDragData });
+                    ScriptCast(this.rootDoc.dropConverter)?.script.run({ dragData: docDragData });
                     added = this.addDocument(docDragData.droppedDocuments);
                 }
                 !added && alert('You cannot perform this move');
diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx
index 60e6815e5..192d48c64 100644
--- a/src/client/views/collections/CollectionTimeView.tsx
+++ b/src/client/views/collections/CollectionTimeView.tsx
@@ -34,8 +34,6 @@ export class CollectionTimeView extends CollectionSubView() {
 
     async componentDidMount() {
         this.props.setContentView?.(this);
-        //const detailView = (await DocCastAsync(this.props.Document.childClickedOpenTemplateView)) || DocUtils.findTemplate("detailView", StrCast(this.rootDoc.type), "");
-        ///const childText = "const embedding = getEmbedding(self); switchView(embedding, detailView); embedding.dropAction='embed'; useRightSplit(embedding, shiftKey); ";
         runInAction(() => {
             this._childClickedScript = ScriptField.MakeScript('openInLightbox(self)', { this: Doc.name });
             this._viewDefDivClick = ScriptField.MakeScript('pivotColumnClick(this,payload)', { payload: 'any' });
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index ed1e0c067..7598bb753 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -3,7 +3,6 @@ import { observer } from 'mobx-react';
 import { Doc, DocListCast, Opt, StrListCast } from '../../../fields/Doc';
 import { DocData, Height, Width } from '../../../fields/DocSymbols';
 import { Id } from '../../../fields/FieldSymbols';
-import { InkTool } from '../../../fields/InkField';
 import { listSpec } from '../../../fields/Schema';
 import { ScriptField } from '../../../fields/ScriptField';
 import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
@@ -90,8 +89,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
     // these should stay in synch with counterparts in DocComponent.ts ViewBoxAnnotatableComponent
     @observable _isAnyChildContentActive = false;
     whenChildContentsActiveChanged = action((isActive: boolean) => this.props.whenChildContentsActiveChanged((this._isAnyChildContentActive = isActive)));
-    isContentActive = (outsideReaction?: boolean) =>
-        Doc.ActiveTool !== InkTool.None || this.props.isContentActive?.() || this.props.Document.forceActive || this.props.isSelected(outsideReaction) || this._isAnyChildContentActive || this.props.rootSelected(outsideReaction) ? true : false;
+    isContentActive = (outsideReaction?: boolean) => (this._isAnyChildContentActive ? true : this.props.isContentActive() ? true : false);
 
     componentWillUnmount() {
         this._isDisposing = true;
@@ -261,7 +259,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
     @observable _renderCount = 1;
     @computed get treeViewElements() {
         TraceMobx();
-        const dropAction = StrCast(this.doc.childDropAction) as dropActionType;
+        const dragAction = StrCast(this.doc.childDragAction) as dropActionType;
         const addDoc = (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => this.addDoc(doc, relativeTo, before);
         const moveDoc = (d: Doc | Doc[], target: Doc | undefined, addDoc: (doc: Doc | Doc[]) => boolean) => this.props.moveDocument?.(d, target, addDoc) || false;
         if (this._renderCount < this.treeChildren.length) setTimeout(action(() => (this._renderCount = Math.min(this.treeChildren.length, this._renderCount + 20))));
@@ -276,7 +274,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
             addDoc,
             this.remove,
             moveDoc,
-            dropAction,
+            dragAction,
             this.props.addDocTab,
             this.props.styleProvider,
             this.screenToLocalTransform,
@@ -383,7 +381,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
     @observable _headerHeight = 0;
     @computed get content() {
         const background = () => this.props.styleProvider?.(this.doc, this.props, StyleProp.BackgroundColor);
-        const pointerEvents = () => (!this.props.isContentActive() && !SnappingManager.GetIsDragging() ? 'none' : undefined);
+        const pointerEvents = () => (this.props.isContentActive() === false ? 'none' : undefined);
         const titleBar = this.props.treeViewHideTitle || this.doc.treeViewHideTitle ? null : this.titleBar;
         return (
             <div style={{ display: 'flex', flexDirection: 'column', height: '100%', pointerEvents: 'all' }}>
@@ -440,12 +438,12 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
                         setContentView={emptyFunction}
                         NativeWidth={returnZero}
                         NativeHeight={returnZero}
-                        pointerEvents={SnappingManager.GetIsDragging() ? returnAll : returnNone}
+                        pointerEvents={this.props.isContentActive() && SnappingManager.GetIsDragging() ? returnAll : returnNone}
                         isAnnotationOverlay={true}
                         isAnnotationOverlayScrollable={true}
                         childDocumentsActive={this.props.isDocumentActive}
                         fieldKey={this.props.fieldKey + '_annotations'}
-                        dropAction={'move'}
+                        dropAction="move"
                         select={emptyFunction}
                         addDocument={this.addAnnotationDocument}
                         removeDocument={this.remAnnotationDocument}
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 7913d3188..c33519afb 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -9,6 +9,7 @@ import { TraceMobx } from '../../../fields/util';
 import { returnEmptyString } from '../../../Utils';
 import { DocUtils } from '../../documents/Documents';
 import { CollectionViewType } from '../../documents/DocumentTypes';
+import { dropActionType } from '../../util/DragManager';
 import { ImageUtils } from '../../util/Import & Export/ImageUtils';
 import { InteractionUtils } from '../../util/InteractionUtils';
 import { ContextMenu } from '../ContextMenu';
@@ -55,7 +56,7 @@ interface CollectionViewProps_ extends FieldViewProps {
     childHideDecorationTitle?: () => boolean;
     childHideResizeHandles?: () => boolean;
     childLayoutTemplate?: () => Doc | undefined; // specify a layout Doc template to use for children of the collection
-    childCanEmbedOnDrag?: boolean;
+    childDragAction?: dropActionType;
     childXPadding?: number;
     childYPadding?: number;
     childLayoutString?: string;
@@ -220,7 +221,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
     childHideResizeHandles = () => this.props.childHideResizeHandles?.() ?? BoolCast(this.Document.childHideResizeHandles);
     childHideDecorationTitle = () => this.props.childHideDecorationTitle?.() ?? BoolCast(this.Document.childHideDecorationTitle);
     childLayoutTemplate = () => this.props.childLayoutTemplate?.() || Cast(this.rootDoc.childLayoutTemplate, Doc, null);
-    isContentActive = (outsideReaction?: boolean) => this.props.isContentActive() || this.isAnyChildContentActive();
+    isContentActive = (outsideReaction?: boolean) => (this.isAnyChildContentActive() ? true : this.props.isContentActive());
 
     render() {
         TraceMobx();
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 3b99339af..97d4d989b 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -583,7 +583,6 @@ export class TabMinimapView extends React.Component<TabMinimapViewProps> {
                     isContentActive={emptyFunction}
                     isAnyChildContentActive={returnFalse}
                     select={emptyFunction}
-                    dropAction={undefined}
                     isSelected={returnFalse}
                     dontRegisterView={true}
                     fieldKey={Doc.LayoutFieldKey(this.props.document)}
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 6bc30c451..91ae2b3cc 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -21,7 +21,7 @@ import { ScriptingGlobals } from '../../util/ScriptingGlobals';
 import { SelectionManager } from '../../util/SelectionManager';
 import { SnappingManager } from '../../util/SnappingManager';
 import { Transform } from '../../util/Transform';
-import { undoBatch, UndoManager } from '../../util/UndoManager';
+import { undoable, undoBatch, UndoManager } from '../../util/UndoManager';
 import { EditableView } from '../EditableView';
 import { TREE_BULLET_WIDTH } from '../global/globalCssVariables.scss';
 import { DocumentView, DocumentViewInternal, DocumentViewProps, OpenWhere, StyleProviderFunc } from '../nodes/DocumentView';
@@ -45,7 +45,7 @@ export interface TreeViewProps {
     dataDoc?: Doc;
     treeViewParent: Doc;
     renderDepth: number;
-    dropAction: dropActionType;
+    dragAction: dropActionType;
     addDocTab: (doc: Doc, where: OpenWhere) => boolean;
     panelWidth: () => number;
     panelHeight: () => number;
@@ -276,7 +276,7 @@ export class TreeView extends React.Component<TreeViewProps> {
     };
     onPointerEnter = (e: React.PointerEvent): void => {
         this.props.isContentActive(true) && Doc.BrushDoc(this.dataDoc);
-        if (e.buttons === 1 && SnappingManager.GetIsDragging()) {
+        if (e.buttons === 1 && SnappingManager.GetIsDragging() && this.props.isContentActive()) {
             this._header.current!.className = 'treeView-header';
             document.removeEventListener('pointermove', this.onDragMove, true);
             document.removeEventListener('pointerup', this.onDragUp, true);
@@ -341,7 +341,7 @@ export class TreeView extends React.Component<TreeViewProps> {
     };
 
     makeFolder = () => {
-        const folder = Docs.Create.TreeDocument([], { title: 'Untitled folder', _stayInCollection: true, isFolder: true });
+        const folder = Docs.Create.TreeDocument([], { title: 'Untitled folder', _dragOnlyWithinContainer: true, isFolder: true });
         TreeView._editTitleOnLoad = { id: folder[Id], parent: this.props.parentTreeView };
         return this.props.addDocument(folder);
     };
@@ -391,7 +391,7 @@ export class TreeView extends React.Component<TreeViewProps> {
         const canAdd = (!this.props.treeView.outlineMode && !StrCast((inside ? this.props.document : this.props.treeViewParent)?.treeViewFreezeChildren).includes('add')) || forceAdd;
         if (canAdd) {
             this.props.parentTreeView instanceof TreeView && (this.props.parentTreeView.dropping = true);
-            const res = UndoManager.RunInTempBatch(() => droppedDocuments.reduce((added, d) => (move ? move(d, undefined, addDoc) || (dropAction === 'proto' ? addDoc(d) : false) : addDoc(d)) || added, false));
+            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);
             return res;
         }
@@ -460,7 +460,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                     addDoc,
                     remDoc,
                     moveDoc,
-                    this.props.dropAction,
+                    this.props.dragAction,
                     this.props.addDocTab,
                     this.titleStyleProvider,
                     this.props.ScreenToLocalTransform,
@@ -585,12 +585,12 @@ export class TreeView extends React.Component<TreeViewProps> {
                             downY = e.clientY;
                             e.stopPropagation();
                         }}
-                        onClick={e => {
+                        onClick={undoable(e => {
                             if (this.props.isContentActive() && Math.abs(e.clientX - downX) < 3 && Math.abs(e.clientY - downY) < 3) {
                                 !this.props.treeView.outlineMode && (this.doc.treeViewSortCriterion = sortKeys[(curSortIndex + 1) % sortKeys.length]);
                                 e.stopPropagation();
                             }
-                        }}>
+                        }, 'sort order')}>
                         {!docs
                             ? null
                             : TreeView.GetChildElements(
@@ -604,7 +604,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                                   addDoc,
                                   remDoc,
                                   moveDoc,
-                                  StrCast(this.doc.childDropAction, this.props.dropAction) as dropActionType,
+                                  StrCast(this.doc.childDragAction, this.props.dragAction) as dropActionType,
                                   this.props.addDocTab,
                                   this.titleStyleProvider,
                                   this.props.ScreenToLocalTransform,
@@ -904,7 +904,6 @@ export class TreeView extends React.Component<TreeViewProps> {
                 hideDecorationTitle={this.props.treeView.outlineMode}
                 hideResizeHandles={this.props.treeView.outlineMode}
                 styleProvider={this.titleStyleProvider}
-                enableDragWhenActive={true}
                 onClickScriptDisable="never" // tree docViews have a script to show fields, etc.
                 docViewPath={this.props.treeView.props.docViewPath}
                 treeViewDoc={this.props.treeView.props.Document}
@@ -914,7 +913,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                 pinToPres={emptyFunction}
                 onClick={this.onChildClick}
                 onDoubleClick={this.onChildDoubleClick}
-                dropAction={this.props.dropAction}
+                dragAction={this.props.dragAction}
                 moveDocument={this.move}
                 removeDocument={this.props.removeDoc}
                 ScreenToLocalTransform={this.getTransform}
@@ -950,7 +949,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                         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,
-                        pointerEvents: !this.props.isContentActive() && !SnappingManager.GetIsDragging() ? 'none' : undefined,
+                        pointerEvents: !this.props.isContentActive() ? 'none' : undefined,
                     }}>
                     {view}
                 </div>
@@ -1132,7 +1131,7 @@ export class TreeView extends React.Component<TreeViewProps> {
         add: (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => boolean,
         remove: undefined | ((doc: Doc | Doc[]) => boolean),
         move: DragManager.MoveFunction,
-        dropAction: dropActionType,
+        dragAction: dropActionType,
         addDocTab: (doc: Doc, where: OpenWhere) => boolean,
         styleProvider: undefined | StyleProviderFunc,
         screenToLocalXf: () => Transform,
@@ -1218,7 +1217,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                         panelHeight={rowHeight}
                         dontRegisterView={dontRegisterView}
                         moveDocument={move}
-                        dropAction={dropAction}
+                        dragAction={dragAction}
                         addDocTab={addDocTab}
                         ScreenToLocalTransform={screenToLocalXf}
                         isContentActive={isContentActive}
@@ -1239,6 +1238,6 @@ export class TreeView extends React.Component<TreeViewProps> {
 
 ScriptingGlobals.add(function TreeView_addNewFolder() {
     TreeView._editTitleOnLoad = { id: Utils.GenerateGuid(), parent: undefined };
-    const opts = { title: 'Untitled folder', _stayInCollection: true, isFolder: true };
+    const opts = { title: 'Untitled folder', _dragOnlyWithinContainer: true, isFolder: true };
     return Doc.AddDocToList(Doc.MyFilesystem, 'data', Docs.Create.TreeDocument([], opts, TreeView._editTitleOnLoad.id));
 });
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 36472dd2e..d7e073c5f 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1240,7 +1240,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         };
     };
 
-    isContentActive = () => this.props.isSelected() || this.props.isContentActive();
+    isContentActive = () => this.props.isContentActive();
 
     @undoBatch
     @action
@@ -1267,7 +1267,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         const engine = this.props.layoutEngine?.() || StrCast(this.props.Document._layoutEngine);
         const pointerEvents = DocumentDecorations.Instance.Interacting
             ? 'none'
-            : this.props.childPointerEvents ?? (this.props.viewDefDivClick || (engine === computePassLayout.name && !this.props.isSelected(true)) ? 'none' : this.props.pointerEvents?.());
+            : this.props.childPointerEvents ?? (this.props.viewDefDivClick || (engine === computePassLayout.name && !this.props.isSelected(true)) || this.isContentActive() === false ? 'none' : this.props.pointerEvents?.());
         return pointerEvents;
     };
     getChildDocView(entry: PoolData) {
@@ -1298,7 +1298,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 childFiltersByRanges={this.childDocRangeFilters}
                 searchFilterDocs={this.searchFilterDocs}
                 isDocumentActive={this.props.childDocumentsActive?.() ? this.props.isDocumentActive : this.isContentActive}
-                isContentActive={this.props.childContentsActive ?? emptyFunction}
+                isContentActive={this.props.childContentsActive ?? this.props.isContentActive() === false ? returnFalse : emptyFunction}
                 focus={this.Document._isGroup ? this.groupFocus : this.isAnnotationOverlay ? this.props.focus : this.focus}
                 addDocTab={this.addDocTab}
                 addDocument={this.props.addDocument}
@@ -1308,10 +1308,9 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
                 docViewPath={this.props.docViewPath}
                 styleProvider={this.getClusterColor}
-                canEmbedOnDrag={this.props.childCanEmbedOnDrag}
+                dragAction={(this.rootDoc.childDragAction ?? this.props.childDragAction) as dropActionType}
                 dataProvider={this.childDataProvider}
                 sizeProvider={this.childSizeProvider}
-                dropAction={StrCast(this.props.Document.childDropAction) as dropActionType}
                 bringToFront={this.bringToFront}
                 layout_showTitle={this.props.childlayout_showTitle}
                 dontRegisterView={this.props.dontRenderDocuments || this.props.dontRegisterView}
@@ -1987,7 +1986,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 onDragOver={e => e.preventDefault()}
                 onContextMenu={this.onContextMenu}
                 style={{
-                    pointerEvents: SnappingManager.GetIsDragging() && this.childDocs.includes(DragManager.docsBeingDragged.lastElement()) ? 'all' : (this.props.pointerEvents?.() as any),
+                    pointerEvents: this.props.isContentActive() && SnappingManager.GetIsDragging() ? 'all' : (this.props.pointerEvents?.() as any),
                     textAlign: this.isAnnotationOverlay ? 'initial' : undefined,
                     transform: `scale(${this.nativeDimScaling || 1})`,
                     width: `${100 / (this.nativeDimScaling || 1)}%`,
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 77cb7f88c..898452ccb 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -386,7 +386,6 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
         newCollection._height = this.Bounds.height;
         newCollection._isGroup = makeGroup;
         newCollection.forceActive = makeGroup;
-        newCollection.enableDragWhenActive = makeGroup;
         newCollection.x = this.Bounds.left;
         newCollection.y = this.Bounds.top;
         newCollection.layout_fitWidth = true;
diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.tsx b/src/client/views/collections/collectionGrid/CollectionGridView.tsx
index e8ae88ae5..cd8b7a0cc 100644
--- a/src/client/views/collections/collectionGrid/CollectionGridView.tsx
+++ b/src/client/views/collections/collectionGrid/CollectionGridView.tsx
@@ -368,7 +368,7 @@ export class CollectionGridView extends CollectionSubView() {
             <div
                 className="collectionGridView-contents"
                 ref={this.createDashEventsTarget}
-                style={{ pointerEvents: !this.props.isContentActive() && !SnappingManager.GetIsDragging() ? 'none' : undefined }}
+                style={{ pointerEvents: !this.props.isContentActive() ? 'none' : undefined }}
                 onContextMenu={this.onContextMenu}
                 onPointerDown={this.onPointerDown}
                 onDrop={this.onExternalDrop}>
diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
index 65578f214..8f90e4444 100644
--- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
+++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
@@ -1,6 +1,6 @@
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { Tooltip } from '@material-ui/core';
-import { action, IReactionDisposer, observable, reaction, runInAction } from 'mobx';
+import { action, IReactionDisposer, observable, reaction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
 import { Doc, Opt } from '../../../../fields/Doc';
@@ -50,34 +50,10 @@ export class CollectionLinearView extends CollectionSubView() {
             width => this.childDocs.length && (this.layoutDoc._width = width),
             { fireImmediately: true }
         );
-
-        this._selectedDisposer = reaction(
-            () => NumCast(this.layoutDoc.selectedIndex),
-            i =>
-                runInAction(() => {
-                    this._selectedIndex = i;
-                    let selected: any = undefined;
-                    this.childLayoutPairs.map(async (pair, ind) => {
-                        const isSelected = this._selectedIndex === ind;
-                        if (isSelected) {
-                            selected = pair;
-                        } else {
-                            ScriptCast(DocCast(pair.layout.proto)?.onPointerUp)?.script.run({ this: pair.layout.proto }, console.log);
-                        }
-                    });
-                    if (selected && selected.layout) {
-                        ScriptCast(DocCast(selected.layout.proto)?.onPointerDown)?.script.run({ this: selected.layout.proto }, console.log);
-                    }
-                }),
-            { fireImmediately: true }
-        );
     }
     protected createDashEventsTarget = (ele: HTMLDivElement | null) => {
-        //used for stacking and masonry view
-        this._dropDisposer && this._dropDisposer();
-        if (ele) {
-            this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc);
-        }
+        this._dropDisposer?.();
+        if (ele) this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc);
     };
 
     dimension = () => NumCast(this.rootDoc._height);
@@ -89,12 +65,8 @@ export class CollectionLinearView extends CollectionSubView() {
 
     @action
     exitLongLinks = () => {
-        if (DocumentLinksButton.StartLink) {
-            if (DocumentLinksButton.StartLink.Document) {
-                action((e: React.PointerEvent<HTMLDivElement>) => {
-                    Doc.UnBrushDoc(DocumentLinksButton.StartLink?.Document as Doc);
-                });
-            }
+        if (DocumentLinksButton.StartLink?.Document) {
+            action((e: React.PointerEvent<HTMLDivElement>) => Doc.UnBrushDoc(DocumentLinksButton.StartLink?.Document as Doc));
         }
         DocumentLinksButton.StartLink = undefined;
         DocumentLinksButton.StartLinkView = undefined;
@@ -201,7 +173,7 @@ export class CollectionLinearView extends CollectionSubView() {
                     moveDocument={this.props.moveDocument}
                     addDocTab={this.props.addDocTab}
                     pinToPres={emptyFunction}
-                    dropAction={StrCast(this.layoutDoc.childDropAction) as dropActionType}
+                    dragAction={(this.layoutDoc.childDragAction ?? this.props.childDragAction) as dropActionType}
                     rootSelected={this.props.isSelected}
                     removeDocument={this.props.removeDocument}
                     ScreenToLocalTransform={docXf}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index 34fa0343d..32b42223b 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -5,7 +5,6 @@ import { Doc, DocListCast } from '../../../../fields/Doc';
 import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
 import { returnFalse } from '../../../../Utils';
 import { DragManager, dropActionType } from '../../../util/DragManager';
-import { SnappingManager } from '../../../util/SnappingManager';
 import { Transform } from '../../../util/Transform';
 import { undoBatch } from '../../../util/UndoManager';
 import { DocumentView } from '../../nodes/DocumentView';
@@ -194,11 +193,7 @@ export class CollectionMulticolumnView extends CollectionSubView() {
         let dropInd = -1;
         if (de.complete.docDragData && this._mainCont) {
             let curInd = -1;
-            de.complete.docDragData?.droppedDocuments.forEach(
-                action((d: Doc) => {
-                    curInd = this.childDocs.indexOf(d);
-                })
-            );
+            de.complete.docDragData?.droppedDocuments.forEach(d => (curInd = this.childDocs.indexOf(d)));
             Array.from(this._mainCont.children).forEach((child, index) => {
                 const brect = child.getBoundingClientRect();
                 if (brect.x < de.x && brect.x + brect.width > de.x) {
@@ -234,7 +229,14 @@ export class CollectionMulticolumnView extends CollectionSubView() {
     onChildDoubleClickHandler = () => ScriptCast(this.Document.onChildDoubleClick);
 
     isContentActive = () => this.props.isSelected() || this.props.isContentActive() || this.props.isAnyChildContentActive();
-    isChildContentActive = () => (((this.props.childDocumentsActive?.() || this.Document._childDocumentsActive) && this.props.isDocumentActive?.() && SnappingManager.GetIsDragging()) || this.isContentActive() ? true : false);
+    isChildContentActive = () => {
+        const childDocsActive = this.props.childDocumentsActive?.() ?? this.rootDoc.childDocumentsActive;
+        return this.props.isContentActive?.() === false || childDocsActive === false
+            ? false //
+            : this.props.isDocumentActive?.() && childDocsActive
+            ? true
+            : undefined;
+    };
     getDisplayDoc = (layout: Doc, dxf: () => Transform, width: () => number, height: () => number) => {
         return (
             <DocumentView
@@ -248,7 +250,7 @@ export class CollectionMulticolumnView extends CollectionSubView() {
                 PanelWidth={width}
                 PanelHeight={height}
                 rootSelected={this.rootSelected}
-                dropAction={StrCast(this.props.Document.childDropAction) as dropActionType}
+                dragAction={(this.props.Document.childDragAction ?? this.props.childDragAction) as dropActionType}
                 onClick={this.onChildClickHandler}
                 onDoubleClick={this.onChildDoubleClickHandler}
                 suppressSetHeight={true}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index bab77ed48..fa3a9f352 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -5,7 +5,6 @@ import { Doc, DocListCast } from '../../../../fields/Doc';
 import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
 import { returnFalse } from '../../../../Utils';
 import { DragManager, dropActionType } from '../../../util/DragManager';
-import { SnappingManager } from '../../../util/SnappingManager';
 import { Transform } from '../../../util/Transform';
 import { undoBatch } from '../../../util/UndoManager';
 import { DocumentView } from '../../nodes/DocumentView';
@@ -194,11 +193,7 @@ export class CollectionMultirowView extends CollectionSubView() {
         let dropInd = -1;
         if (de.complete.docDragData && this._mainCont) {
             let curInd = -1;
-            de.complete.docDragData?.droppedDocuments.forEach(
-                action((d: Doc) => {
-                    curInd = this.childDocs.indexOf(d);
-                })
-            );
+            de.complete.docDragData?.droppedDocuments.forEach(d => (curInd = this.childDocs.indexOf(d)));
             Array.from(this._mainCont.children).forEach((child, index) => {
                 const brect = child.getBoundingClientRect();
                 if (brect.y < de.y && brect.y + brect.height > de.y) {
@@ -234,7 +229,14 @@ export class CollectionMultirowView extends CollectionSubView() {
     onChildDoubleClickHandler = () => ScriptCast(this.Document.onChildDoubleClick);
 
     isContentActive = () => this.props.isSelected() || this.props.isContentActive() || this.props.isAnyChildContentActive();
-    isChildContentActive = () => (((this.props.childDocumentsActive?.() || this.Document._childDocumentsActive) && this.props.isDocumentActive?.() && SnappingManager.GetIsDragging()) || this.isContentActive() ? true : false);
+    isChildContentActive = () => {
+        const childDocsActive = this.props.childDocumentsActive?.() ?? this.rootDoc.childDocumentsActive;
+        return this.props.isContentActive?.() === false || childDocsActive === false
+            ? false //
+            : this.props.isDocumentActive?.() && childDocsActive
+            ? true
+            : undefined;
+    };
     getDisplayDoc = (layout: Doc, dxf: () => Transform, width: () => number, height: () => number) => {
         return (
             <DocumentView
@@ -248,7 +250,7 @@ export class CollectionMultirowView extends CollectionSubView() {
                 PanelWidth={width}
                 PanelHeight={height}
                 rootSelected={this.rootSelected}
-                dropAction={StrCast(this.props.Document.childDropAction) as dropActionType}
+                dropAction={StrCast(this.rootDoc.childDragAction) as dropActionType}
                 onClick={this.onChildClickHandler}
                 onDoubleClick={this.onChildDoubleClickHandler}
                 ScreenToLocalTransform={dxf}
@@ -257,6 +259,7 @@ export class CollectionMultirowView extends CollectionSubView() {
                 hideResizeHandles={this.props.childHideResizeHandles?.()}
                 hideDecorationTitle={this.props.childHideDecorationTitle?.()}
                 fitContentsToBox={this.props.fitContentsToBox}
+                dragAction={this.props.childDragAction}
                 focus={this.props.focus}
                 childFilters={this.childDocFilters}
                 childFiltersByRanges={this.childDocRangeFilters}
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 15424de98..06b227b4b 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -952,7 +952,7 @@ class CollectionSchemaViewDocs extends React.Component<CollectionSchemaViewDocsP
                                 styleProvider={DefaultStyleProvider}
                                 waitForDoubleClickToClick={returnNever}
                                 defaultDoubleClick={returnIgnore}
-                                enableDragWhenActive={true}
+                                dragAction="move"
                                 onClickScriptDisable="always"
                                 focus={this.props.schema.focusDocument}
                                 childFilters={this.props.schema.childDocFilters}
@@ -970,7 +970,6 @@ class CollectionSchemaViewDocs extends React.Component<CollectionSchemaViewDocsP
                                 hideLinkAnchors={true}
                                 layout_fitWidth={returnTrue}
                                 scriptContext={this}
-                                canEmbedOnDrag={true}
                             />
                         </div>
                     );
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 4f3503751..e8e606030 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -53,13 +53,13 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
     };
 
     onPointerEnter = (e: any) => {
-        if (!SnappingManager.GetIsDragging()) return;
-        document.removeEventListener('pointermove', this.onPointerMove);
-        document.addEventListener('pointermove', this.onPointerMove);
+        if (SnappingManager.GetIsDragging() && this.props.isContentActive()) {
+            document.removeEventListener('pointermove', this.onPointerMove);
+            document.addEventListener('pointermove', this.onPointerMove);
+        }
     };
 
     onPointerMove = (e: any) => {
-        if (!SnappingManager.GetIsDragging()) return;
         const dragIsRow = DragManager.docsBeingDragged.some(doc => doc.embedContainer === this.schemaDoc); //  this.schemaView?._selectedDocs.has(doc) ?? false;
 
         if (this._ref && dragIsRow) {
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 97264508c..a958f53ea 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -76,7 +76,7 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
             isSelected: returnFalse,
             setHeight: returnFalse,
             select: emptyFunction,
-            dropAction: 'embed',
+            dragAction: 'move',
             bringToFront: emptyFunction,
             renderDepth: 1,
             isContentActive: returnFalse,
diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx
index 5af05e491..9ceac3b8c 100644
--- a/src/client/views/linking/LinkMenuItem.tsx
+++ b/src/client/views/linking/LinkMenuItem.tsx
@@ -78,7 +78,7 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
             e,
             e => {
                 const dragData = new DragManager.DocumentDragData([this.props.linkDoc], 'embed');
-                dragData.removeDropProperties = ['hidden'];
+                dragData.dropPropertiesToRemove = ['hidden'];
                 DragManager.StartDocumentDrag([this._editRef.current!], dragData, e.x, e.y);
                 return true;
             },
diff --git a/src/client/views/linking/LinkPopup.tsx b/src/client/views/linking/LinkPopup.tsx
index 664a0fa4f..745efea08 100644
--- a/src/client/views/linking/LinkPopup.tsx
+++ b/src/client/views/linking/LinkPopup.tsx
@@ -70,7 +70,6 @@ export class LinkPopup extends React.Component<LinkPopupProps> {
                         linkSearch={true}
                         linkCreated={this.props.linkCreated}
                         fieldKey="data"
-                        dropAction="move"
                         isSelected={returnTrue}
                         isContentActive={returnTrue}
                         select={returnTrue}
diff --git a/src/client/views/nodes/ComparisonBox.scss b/src/client/views/nodes/ComparisonBox.scss
index 660045a6f..a12f1c12b 100644
--- a/src/client/views/nodes/ComparisonBox.scss
+++ b/src/client/views/nodes/ComparisonBox.scss
@@ -93,4 +93,4 @@
             display: flex;
         }
     }
-}
\ No newline at end of file
+}
diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx
index e6a4635c0..d747c4527 100644
--- a/src/client/views/nodes/ComparisonBox.tsx
+++ b/src/client/views/nodes/ComparisonBox.tsx
@@ -2,11 +2,10 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { action, computed, observable } from 'mobx';
 import { observer } from 'mobx-react';
 import { Doc, Opt } from '../../../fields/Doc';
-import { Cast, NumCast, StrCast } from '../../../fields/Types';
+import { DocCast, NumCast, StrCast } from '../../../fields/Types';
 import { emptyFunction, returnFalse, returnNone, returnZero, setupMoveUpEvents } from '../../../Utils';
-import { Docs } from '../../documents/Documents';
+import { Docs, DocUtils } from '../../documents/Documents';
 import { DragManager } from '../../util/DragManager';
-import { SnappingManager } from '../../util/SnappingManager';
 import { undoBatch } from '../../util/UndoManager';
 import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent';
 import { StyleProp } from '../StyleProvider';
@@ -32,15 +31,12 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
     get clipWidthKey() {
         return '_' + this.props.fieldKey + '_clipWidth';
     }
-
     componentDidMount() {
         this.props.setContentView?.(this);
     }
-
     protected createDropTarget = (ele: HTMLDivElement | null, fieldKey: string, disposerId: number) => {
         this._disposers[disposerId]?.();
         if (ele) {
-            // create disposers identified by disposerId to remove drag & drop listeners
             this._disposers[disposerId] = DragManager.MakeDropTarget(ele, (e, dropEvent) => this.internalDrop(e, dropEvent, fieldKey), this.layoutDoc);
         }
     };
@@ -50,29 +46,40 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
         if (dropEvent.complete.docDragData) {
             event.stopPropagation(); // prevent parent Doc from registering new position so that it snaps back into place
             const droppedDocs = dropEvent.complete.docDragData?.droppedDocuments;
-            droppedDocs.lastElement().embedContainer = this.dataDoc;
-            this.dataDoc[fieldKey] = droppedDocs.lastElement();
+            const res = dropEvent.complete.docDragData.moveDocument?.(droppedDocs, this.rootDoc, (doc: Doc | Doc[]) => this.addDoc(doc instanceof Doc ? doc : doc.lastElement(), fieldKey));
+            res && (droppedDocs.lastElement().embedContainer = this.dataDoc);
+            return res;
         }
     };
 
     private registerSliding = (e: React.PointerEvent<HTMLDivElement>, targetWidth: number) => {
-        e.button !== 2 &&
+        if (e.button !== 2) {
             setupMoveUpEvents(
                 this,
                 e,
                 this.onPointerMove,
                 emptyFunction,
+                action((e, doubleTap) => {
+                    if (doubleTap) {
+                        this._isAnyChildContentActive = true;
+                        if (!this.dataDoc[this.fieldKey + '_1']) this.dataDoc[this.fieldKey + '_1'] = DocUtils.copyDragFactory(Doc.UserDoc().emptyNote as Doc);
+                        if (!this.dataDoc[this.fieldKey + '_2']) this.dataDoc[this.fieldKey + '_2'] = DocUtils.copyDragFactory(Doc.UserDoc().emptyNote as Doc);
+                    }
+                }),
+                false,
+                undefined,
                 action(() => {
-                    // on click, animate slider movement to the targetWidth
+                    if (this._isAnyChildContentActive) return;
                     this._animating = 'all 200ms';
+                    // on click, animate slider movement to the targetWidth
                     this.layoutDoc[this.clipWidthKey] = (targetWidth * 100) / this.props.PanelWidth();
                     setTimeout(
                         action(() => (this._animating = '')),
                         200
                     );
-                }),
-                false
+                })
             );
+        }
     };
 
     @action
@@ -86,7 +93,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
 
     getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => {
         const anchor = Docs.Create.ConfigDocument({
-            title: 'ImgAnchor:' + this.rootDoc.title,
+            title: 'CompareAnchor:' + this.rootDoc.title,
             // set presentation timing properties for restoring view
             presTransition: 1000,
             annotationOn: this.rootDoc,
@@ -105,12 +112,29 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
         e.stopPropagation; // prevent click event action (slider movement) in registerSliding
         delete this.dataDoc[fieldKey];
     };
+    moveDoc = (doc: Doc, addDocument: (document: Doc | Doc[]) => boolean, which: string) => this.remDoc(doc, which) && addDocument(doc);
+    addDoc = (doc: Doc, which: string) => {
+        this.dataDoc[which] = doc;
+        return true;
+    };
+    remDoc = (doc: Doc, which: string) => {
+        if (this.dataDoc[which] === doc) {
+            this.dataDoc[which] = undefined;
+            return true;
+        }
+        return false;
+    };
+
+    whenChildContentsActiveChanged = action((isActive: boolean) => (this._isAnyChildContentActive = isActive));
 
     docStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewProps>, property: string): any => {
         if (property === StyleProp.PointerEvents) return 'none';
         return this.props.styleProvider?.(doc, props, property);
     };
-
+    moveDoc1 = (doc: Doc | Doc[], targetCol: Doc | undefined, addDoc: any) => (doc instanceof Doc ? [doc] : doc).reduce((res, doc: Doc) => res && this.moveDoc(doc, addDoc, this.fieldKey + '_1'), true);
+    moveDoc2 = (doc: Doc | Doc[], targetCol: Doc | undefined, addDoc: any) => (doc instanceof Doc ? [doc] : doc).reduce((res, doc: Doc) => res && this.moveDoc(doc, addDoc, this.fieldKey + '_2'), true);
+    remDoc1 = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((res, doc) => res && this.remDoc(doc, this.fieldKey + '_1'), true);
+    remDoc2 = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((res, doc) => res && this.remDoc(doc, this.fieldKey + '_2'), true);
     render() {
         const clearButton = (which: string) => {
             return (
@@ -118,33 +142,35 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
                     className={`clear-button ${which}`}
                     onPointerDown={e => e.stopPropagation()} // prevent triggering slider movement in registerSliding
                     onClick={e => this.clearDoc(e, which)}>
-                    <FontAwesomeIcon className={`clear-button ${which}`} icon={'times'} size="sm" />
+                    <FontAwesomeIcon className={`clear-button ${which}`} icon="times" size="sm" />
                 </div>
             );
         };
         const displayDoc = (which: string) => {
-            const whichDoc = Cast(this.dataDoc[which], Doc, null);
-            // if (whichDoc?.type === DocumentType.MARKER) whichDoc = Cast(whichDoc.annotationOn, Doc, null);
-            const targetDoc = Cast(whichDoc?.annotationOn, Doc, null) ?? whichDoc;
-            return whichDoc ? (
+            const whichDoc = DocCast(this.dataDoc[which]);
+            const targetDoc = DocCast(whichDoc?.annotationOn, whichDoc);
+            return targetDoc ? (
                 <>
                     <DocumentView
                         {...this.props}
+                        Document={targetDoc}
+                        DataDoc={undefined}
+                        moveDocument={which.endsWith('1') ? this.moveDoc1 : this.moveDoc2}
+                        removeDocument={which.endsWith('1') ? this.remDoc1 : this.remDoc2}
                         NativeWidth={returnZero}
                         NativeHeight={returnZero}
-                        isContentActive={returnFalse}
+                        isContentActive={emptyFunction}
                         isDocumentActive={returnFalse}
-                        styleProvider={this.docStyleProvider}
-                        Document={targetDoc}
-                        DataDoc={undefined}
+                        whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
+                        styleProvider={this._isAnyChildContentActive ? this.props.styleProvider : this.docStyleProvider}
                         hideLinkButton={true}
-                        pointerEvents={returnNone}
+                        pointerEvents={this._isAnyChildContentActive ? undefined : returnNone}
                     />
                     {clearButton(which)}
                 </> // placeholder image if doc is missing
             ) : (
                 <div className="placeholder">
-                    <FontAwesomeIcon className="upload-icon" icon={'cloud-upload-alt'} size="lg" />
+                    <FontAwesomeIcon className="upload-icon" icon="cloud-upload-alt" size="lg" />
                 </div>
             );
         };
@@ -157,7 +183,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
         };
 
         return (
-            <div className={`comparisonBox${this.props.isContentActive() || SnappingManager.GetIsDragging() ? '-interactive' : ''}` /* change className to easily disable/enable pointer events in CSS */}>
+            <div className={`comparisonBox${this.props.isContentActive() ? '-interactive' : ''}` /* change className to easily disable/enable pointer events in CSS */}>
                 {displayBox(`${this.fieldKey}_2`, 1, this.props.PanelWidth() - 3)}
                 <div className="clip-div" style={{ width: this.clipWidth + '%', transition: this._animating, background: StrCast(this.layoutDoc._backgroundColor, 'gray') }}>
                     {displayBox(`${this.fieldKey}_1`, 0, 0)}
@@ -169,7 +195,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
                         left: `calc(${this.clipWidth + '%'} - 0.5px)`,
                         cursor: this.clipWidth < 5 ? 'e-resize' : this.clipWidth / 100 > (this.props.PanelWidth() - 5) / this.props.PanelWidth() ? 'w-resize' : undefined,
                     }}
-                    onPointerDown={e => this.registerSliding(e, this.props.PanelWidth() / 2)} /* if clicked, return slide-bar to center */
+                    onPointerDown={e => !this._isAnyChildContentActive && this.registerSliding(e, this.props.PanelWidth() / 2)} /* if clicked, return slide-bar to center */
                 >
                     <div className="slide-handle" />
                 </div>
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 23148ed34..5470a72f5 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -14,7 +14,7 @@ import { ScriptField } from '../../../fields/ScriptField';
 import { BoolCast, Cast, DocCast, ImageCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
 import { AudioField } from '../../../fields/URLField';
 import { GetEffectiveAcl, TraceMobx } from '../../../fields/util';
-import { emptyFunction, isTargetChildOf as isParentOf, lightOrDark, return18, returnEmptyString, returnFalse, returnTrue, returnVal, returnZero, simulateMouseClick, Utils } from '../../../Utils';
+import { emptyFunction, isTargetChildOf as isParentOf, lightOrDark, returnEmptyString, returnFalse, returnTrue, returnVal, simulateMouseClick, Utils } from '../../../Utils';
 import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils';
 import { DocServer } from '../../DocServer';
 import { Docs, DocUtils } from '../../documents/Documents';
@@ -47,6 +47,7 @@ import { DocumentLinksButton } from './DocumentLinksButton';
 import './DocumentView.scss';
 import { FieldViewProps } from './FieldView';
 import { FormattedTextBox } from './formattedText/FormattedTextBox';
+import { KeyValueBox } from './KeyValueBox';
 import { LinkAnchorBox } from './LinkAnchorBox';
 import { PresEffect, PresEffectDirection } from './trails';
 import { PinProps, PresBox } from './trails/PresBox';
@@ -163,6 +164,7 @@ export interface DocumentViewSharedProps {
     docViewPath: () => DocumentView[];
     childHideDecorationTitle?: () => boolean;
     childHideResizeHandles?: () => boolean;
+    childDragAction?: dropActionType; // allows child documents to be dragged out of collection without holding the embedKey or dragging the doc decorations title bar.
     dataTransition?: string; // specifies animation transition - used by collectionPile and potentially other layout engines when changing the size of documents so that the change won't be abrupt
     styleProvider: Opt<StyleProviderFunc>;
     setTitleFocus?: () => void;
@@ -182,7 +184,7 @@ export interface DocumentViewSharedProps {
     pinToPres: (document: Doc, pinProps: PinProps) => void;
     ScreenToLocalTransform: () => Transform;
     bringToFront: (doc: Doc, sendToBack?: boolean) => void;
-    canEmbedOnDrag?: boolean;
+    dragAction?: dropActionType;
     treeViewDoc?: Doc;
     xPadding?: number;
     yPadding?: number;
@@ -194,7 +196,6 @@ export interface DocumentViewSharedProps {
     forceAutoHeight?: boolean;
     disableBrushing?: boolean; // should highlighting for this view be disabled when same document in another view is hovered over.
     onClickScriptDisable?: 'never' | 'always'; // undefined = only when selected
-    enableDragWhenActive?: boolean;
     waitForDoubleClickToClick?: () => 'never' | 'always' | undefined;
     defaultDoubleClick?: () => 'default' | 'ignore' | undefined;
     pointerEvents?: () => Opt<string>;
@@ -314,7 +315,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     @computed get titleHeight() {
         return this.props?.styleProvider?.(this.layoutDoc, this.props, StyleProp.TitleHeight) || 0;
     }
-    @computed get pointerEvents(): 'none' | 'all' | 'visiblePainted' | undefined {
+    get pointerEvents(): 'none' | 'all' | 'visiblePainted' | undefined {
         return this.props.styleProvider?.(this.Document, this.props, StyleProp.PointerEvents + (this.props.isSelected() ? ':selected' : ''));
     }
     @computed get finalLayoutKey() {
@@ -355,11 +356,16 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     componentDidMount() {
         this.setupHandlers();
     }
-
+    preDropFunc = (e: Event, de: DragManager.DropEvent, targetAction: dropActionType) => {
+        if (de.complete.docDragData && this.isContentActive()) {
+            targetAction && (de.complete.docDragData.dropAction = targetAction);
+            e.stopPropagation();
+        }
+    };
     setupHandlers() {
         this.cleanupHandlers(false);
         if (this._mainCont.current) {
-            this._dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, this.drop.bind(this), this.props.Document);
+            this._dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, this.drop.bind(this), this.props.Document, this.preDropFunc);
             this._multiTouchDisposer = InteractionUtils.MakeMultiTouchTarget(this._mainCont.current, this.onTouchStart.bind(this));
             this._holdDisposer = InteractionUtils.MakeHoldTouchTarget(this._mainCont.current, this.handle1PointerHoldStart.bind(this));
         }
@@ -387,7 +393,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
             dragData.treeViewDoc = this.props.treeViewDoc;
             dragData.removeDocument = this.props.removeDocument;
             dragData.moveDocument = this.props.moveDocument;
-            dragData.canEmbed = this.props.canEmbedOnDrag;
+            dragData.canEmbed = this.rootDoc.dragAction ?? this.props.dragAction ? true : false;
             const ffview = this.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView;
             ffview && runInAction(() => (ffview.ChildDrag = this.props.DocumentView()));
             DragManager.StartDocumentDrag(
@@ -478,7 +484,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                             : '';
                         DocumentViewInternal.addDocTabFunc = oldFunc;
                     };
-                    clickFunc = () => (this.props.Document.dontUndo ? func() : UndoManager.RunInBatch(func, 'click ' + this.rootDoc.title));
+                    clickFunc = () => UndoManager.RunInBatch(func, 'click ' + this.rootDoc.title);
                 } else {
                     // onDragStart implies a button doc that we don't want to select when clicking. RootDocument & isTemplateForField implies we're clicking on part of a template instance and we want to select the whole template, not the part
                     if ((this.layoutDoc.onDragStart || this.props.Document.rootDocument) && !(e.ctrlKey || e.button > 0)) {
@@ -506,7 +512,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     onPointerDown = (e: React.PointerEvent): void => {
         this._longPressSelector = setTimeout(() => {
             if (DocumentView.LongPress) {
-                if (this.rootDoc.dontUndo) {
+                if (this.rootDoc.undoIgnoreFields) {
                     runInAction(() => (UndoStack.HideInline = !UndoStack.HideInline));
                 } else {
                     this.props.select(false);
@@ -535,7 +541,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                 //if (this.props.isSelected(true) && this.rootDoc.type !== DocumentType.PDF && this.layoutDoc._type_collection !== CollectionViewType.Docking) e.preventDefault();
 
                 // listen to move events if document content isn't active or document is draggable
-                if (!this.layoutDoc._lockedPosition && (!this.isContentActive() || this.props.enableDragWhenActive || this.rootDoc.enableDragWhenActive)) {
+                if (!this.layoutDoc._lockedPosition && (!this.isContentActive() || this.props.dragAction || this.rootDoc.dragAction)) {
                     document.addEventListener('pointermove', this.onPointerMove);
                 }
             }
@@ -549,7 +555,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
 
         if (!Utils.isClick(e.clientX, e.clientY, this._downX, this._downY, Date.now())) {
             this.cleanupPointerEvents();
-            this.startDragging(this._downX, this._downY, ((e.ctrlKey || e.altKey) && 'embed') || ((this.Document.dropAction || this.props.dropAction || undefined) as dropActionType));
+            this.startDragging(this._downX, this._downY, ((e.ctrlKey || e.altKey) && 'embed') || ((this.Document.dragAction || this.props.dragAction || undefined) as dropActionType));
         }
     };
 
@@ -608,10 +614,12 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     @undoBatch
     @action
     drop = (e: Event, de: DragManager.DropEvent) => {
-        if (this.props.dontRegisterView || this.props.LayoutTemplateString?.includes(LinkAnchorBox.name)) return;
+        if (this.props.dontRegisterView || this.props.LayoutTemplateString?.includes(LinkAnchorBox.name)) return false;
         if (this.props.Document === Doc.ActiveDashboard) {
+            e.stopPropagation();
             alert((e.target as any)?.closest?.('*.lm_content') ? "You can't perform this move most likely because you don't have permission to modify the destination." : 'Linking to document tabs not yet supported. Drop link on document content.');
-            return;
+            e.preventDefault();
+            return true;
         }
         const linkdrag = de.complete.annoDragData ?? de.complete.linkDragData;
         if (linkdrag) {
@@ -625,8 +633,10 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                     const dropDoc = de.complete.annoDragData?.dropDocument ?? this._componentView?.getAnchor?.(true) ?? this.rootDoc;
                     de.complete.linkDocument = DocUtils.MakeLink(linkdrag.linkSourceDoc, dropDoc, {}, undefined, [de.x, de.y - 50]);
                 }
+                return true;
             }
         }
+        return false;
     };
 
     @undoBatch
@@ -851,7 +861,10 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     setHeight = (height: number) => (this.layoutDoc._height = height);
     setContentView = action((view: { getAnchor?: (addAsAnnotation: boolean) => Doc; forward?: () => boolean; back?: () => boolean }) => (this._componentView = view));
     isContentActive = (outsideReaction?: boolean): boolean | undefined => {
-        return this.props.isContentActive() === false
+        //  true  - if the document has been activated directly or indirectly (by having its children selected)
+        //  false - if its pointer events are explicitly turned off or if it's container tells it that it's inactive
+        // undefined - it is not active, but it should be responsive to actions that might active it or its contents (eg clicking)
+        return this.props.isContentActive() === false || this.props.pointerEvents?.() === 'none' || (this.rootDoc.pointerEvents === 'none' && !StrCast(this.props.LayoutTemplateString).includes(KeyValueBox.name))
             ? false
             : Doc.ActiveTool !== InkTool.None ||
               SnappingManager.GetIsDragging() ||
@@ -871,17 +884,18 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                 .some(doc => Doc.AreProtosEqual(DocCast(doc.annotationOn), this.rootDoc));
         const childOverlayed = () => Array.from(DocumentManager._overlayViews).some(view => Doc.AreProtosEqual(view.rootDoc, this.rootDoc));
         return !this.props.LayoutTemplateString &&
-            !this.props.isSelected() &&
+            !this.isContentActive() &&
             LightboxView.LightboxDoc !== this.rootDoc &&
             this.thumb &&
             !Doc.AreProtosEqual(DocumentLinksButton.StartLink, this.rootDoc) &&
-            ((!childHighlighted() && !childOverlayed() && !Doc.isBrushedHighlightedDegree(this.rootDoc)) || this.rootDoc._type_collection === CollectionViewType.Docking) &&
-            !this._componentView?.isAnyChildContentActive?.()
+            ((!childHighlighted() && !childOverlayed() && !Doc.isBrushedHighlightedDegree(this.rootDoc)) || this.rootDoc._type_collection === CollectionViewType.Docking)
             ? true
             : false;
     };
     childFilters = () => [...this.props.childFilters(), ...StrListCast(this.layoutDoc.childFilters)];
-    contentPointerEvents = () => (!this.disableClickScriptFunc && this.onClickHandler ? 'none' : this.pointerEvents);
+
+    /// disable pointer events on content when there's an enabled onClick script, or if contents are marked inactive
+    contentPointerEvents = () => ((!this.disableClickScriptFunc && this.onClickHandler) || this.isContentActive() === false ? 'none' : this.pointerEvents);
     @computed get contents() {
         TraceMobx();
         const isInk = StrCast(this.layoutDoc.layout).includes(InkingStroke.name) && !this.props.LayoutTemplateString;
@@ -889,7 +903,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
             <div
                 className="documentView-contentsView"
                 style={{
-                    pointerEvents: (isInk ? 'none' : this.pointerEvents) ?? 'all',
+                    pointerEvents: (isInk ? 'none' : this.contentPointerEvents()) ?? 'all',
                     height: this.headerMargin ? `calc(100% - ${this.headerMargin}px)` : undefined,
                 }}>
                 {!this._retryThumb || !this.thumbShown() ? null : (
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 85dd779fc..4ebf22ddf 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -45,7 +45,7 @@ export interface FieldViewProps extends DocumentViewSharedProps {
 @observer
 export class FieldView extends React.Component<FieldViewProps> {
     public static LayoutString(fieldType: { name: string }, fieldStr: string) {
-        return `<${fieldType.name} {...props} fieldKey={'${fieldStr}'}/>`; //e.g., "<ImageBox {...props} fieldKey={"data} />"
+        return `<${fieldType.name} {...props} fieldKey={'${fieldStr}'}/>`; //e.g., "<ImageBox {...props} fieldKey={'data'} />"
     }
 
     @computed
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 9acbee1e7..64d6814df 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -387,7 +387,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                     ref={this._overlayIconRef}
                     onPointerDown={e => setupMoveUpEvents(e.target, e, returnFalse, emptyFunction, e => (this.rootDoc[`_${this.fieldKey}_usePath`] = usePath === undefined ? 'alternate' : usePath === 'alternate' ? 'alternate:hover' : undefined))}
                     style={{
-                        display: (SnappingManager.GetIsDragging() && DragManager.DocDragData?.canEmbed) || DocListCast(this.dataDoc[this.fieldKey + '-alternates']).length ? 'block' : 'none',
+                        display: (this.props.isContentActive() !== false && DragManager.DocDragData?.canEmbed) || DocListCast(this.dataDoc[this.fieldKey + '-alternates']).length ? 'block' : 'none',
                         width: 'min(10%, 25px)',
                         height: 'min(10%, 25px)',
                         background: usePath === undefined ? 'white' : usePath === 'alternate' ? 'black' : 'gray',
@@ -505,7 +505,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                     }
                 })}
                 style={{
-                    display: !SnappingManager.GetIsDragging() && this.props.thumbShown?.() ? 'none' : undefined,
+                    display: !this.props.isContentActive() && this.props.thumbShown?.() ? 'none' : undefined,
                     width: this.props.PanelWidth() ? undefined : `100%`,
                     height: this.props.PanelWidth() ? undefined : `100%`,
                     pointerEvents: this.layoutDoc._lockedPosition ? 'none' : undefined,
diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx
index 5b6b0b5a7..a6712a3db 100644
--- a/src/client/views/nodes/KeyValueBox.tsx
+++ b/src/client/views/nodes/KeyValueBox.tsx
@@ -213,18 +213,18 @@ export class KeyValueBox extends React.Component<FieldViewProps> {
         document.addEventListener('pointerup', this.onDividerUp);
     };
 
-    getFieldView = async () => {
+    getFieldView = () => {
         const rows = this.rows.filter(row => row.isChecked);
         if (rows.length > 1) {
-            const parent = Docs.Create.StackingDocument([], { _layout_autoHeight: true, _width: 300, title: `field views for ${DocCast(this.props.Document.data).title}`, _chromeHidden: true });
+            const parent = Docs.Create.StackingDocument([], { _layout_autoHeight: true, _width: 300, title: `field views for ${DocCast(this.props.Document).title}`, _chromeHidden: true });
             for (const row of rows) {
-                const field = this.createFieldView(DocCast(this.props.Document.data), row);
+                const field = this.createFieldView(DocCast(this.props.Document), row);
                 field && Doc.AddDocToList(parent, 'data', field);
                 row.uncheck();
             }
             return parent;
         }
-        return rows.length ? this.createFieldView(DocCast(this.props.Document.data), rows.lastElement()) : undefined;
+        return rows.length ? this.createFieldView(DocCast(this.props.Document), rows.lastElement()) : undefined;
     };
 
     createFieldView = (templateDoc: Doc, row: KeyValuePair) => {
diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx
index d0db60b37..01acdccb7 100644
--- a/src/client/views/nodes/KeyValuePair.tsx
+++ b/src/client/views/nodes/KeyValuePair.tsx
@@ -67,7 +67,6 @@ export class KeyValuePair extends React.Component<KeyValuePairProps> {
             isSelected: returnFalse,
             setHeight: returnFalse,
             select: emptyFunction,
-            dropAction: 'embed',
             bringToFront: emptyFunction,
             renderDepth: 1,
             isContentActive: returnFalse,
diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx
index e86b881a8..9bcd04cf5 100644
--- a/src/client/views/nodes/LinkAnchorBox.tsx
+++ b/src/client/views/nodes/LinkAnchorBox.tsx
@@ -47,7 +47,7 @@ export class LinkAnchorBox extends ViewBoxBaseComponent<FieldViewProps>() {
             if (separation > 100) {
                 const dragData = new DragManager.DocumentDragData([this.rootDoc]);
                 dragData.dropAction = 'embed';
-                dragData.removeDropProperties = ['link_anchor_1_x', 'link_anchor_1_y', 'link_anchor_2_x', 'link_anchor_2_y', 'onClick'];
+                dragData.dropPropertiesToRemove = ['link_anchor_1_x', 'link_anchor_1_y', 'link_anchor_2_x', 'link_anchor_2_y', 'onClick'];
                 DragManager.StartDocumentDrag([this._ref.current!], dragData, pt[0], pt[1]);
                 return true;
             } else {
diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx
index 93e54ffb7..de0b57fd7 100644
--- a/src/client/views/nodes/MapBox/MapBox.tsx
+++ b/src/client/views/nodes/MapBox/MapBox.tsx
@@ -512,9 +512,8 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         return this.addDocument(doc, annotationKey);
     };
 
-    pointerEvents = () => {
-        return this.props.isContentActive() && this.props.pointerEvents?.() !== 'none' && !MarqueeOptionsMenu.Instance.isShown() ? 'all' : SnappingManager.GetIsDragging() ? undefined : 'none';
-    };
+    pointerEvents = () => (this.props.isContentActive() && !MarqueeOptionsMenu.Instance.isShown() ? 'all' : 'none');
+
     @computed get annotationLayer() {
         return (
             <div className="mapBox-annotationLayer" style={{ height: Doc.NativeHeight(this.Document) || undefined }} ref={this._annotationLayer}>
diff --git a/src/client/views/nodes/MapBox/MapBox2.tsx b/src/client/views/nodes/MapBox/MapBox2.tsx
index 72f37b62c..a9154c5bb 100644
--- a/src/client/views/nodes/MapBox/MapBox2.tsx
+++ b/src/client/views/nodes/MapBox/MapBox2.tsx
@@ -510,7 +510,7 @@ export class MapBox2 extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     };
 
     pointerEvents = () => {
-        return this.props.isContentActive() && this.props.pointerEvents?.() !== 'none' && !MarqueeOptionsMenu.Instance.isShown() ? 'all' : SnappingManager.GetIsDragging() ? undefined : 'none';
+        return this.props.isContentActive() === false ? 'none' : this.props.isContentActive() && this.props.pointerEvents?.() !== 'none' && !MarqueeOptionsMenu.Instance.isShown() ? 'all' : SnappingManager.GetIsDragging() ? undefined : 'none';
     };
     @computed get annotationLayer() {
         return (
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 6d040ca1a..fd4c6366b 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -559,7 +559,6 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
             </div>
         );
     }
-    isPdfContentActive = () => this.isAnyChildContentActive() || this.props.isSelected() || (this.props.renderDepth === 0 && LightboxView.IsLightboxDocView(this.props.docViewPath()));
     @computed get renderPdfView() {
         TraceMobx();
         const previewScale = this._previewNativeWidth ? 1 - this.sidebarWidth() / this._previewNativeWidth : 1;
@@ -592,7 +591,6 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                         pdf={this._pdf}
                         focus={this.focus}
                         url={this.pdfUrl!.url.pathname}
-                        isContentActive={this.isPdfContentActive}
                         anchorMenuClick={this.anchorMenuClick}
                         loaded={!Doc.NativeAspect(this.dataDoc) ? this.loaded : undefined}
                         setPdfViewer={this.setPdfViewer}
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 16705a6b3..34a1229ba 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -918,7 +918,6 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 ScreenToLocalTransform={this.scrollXf}
                 NativeDimScaling={returnOne}
                 focus={this.focus}
-                dropAction="embed"
                 childFilters={childFilters}
                 select={emptyFunction}
                 isAnyChildContentActive={returnFalse}
@@ -1003,8 +1002,11 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         }
         return this.props.styleProvider?.(doc, props, property);
     };
-    pointerEvents = () => (!this._draggingSidebar && this.props.isContentActive() && this.props.pointerEvents?.() !== 'none' && !MarqueeOptionsMenu.Instance?.isShown() ? 'all' : SnappingManager.GetIsDragging() ? undefined : 'none');
-    annotationPointerEvents = () => (this._isAnnotating || SnappingManager.GetIsDragging() || Doc.ActiveTool !== InkTool.None ? 'all' : 'none');
+    pointerEvents = () =>
+        !this._draggingSidebar && this.props.isContentActive() && !MarqueeOptionsMenu.Instance?.isShown()
+            ? 'all' //
+            : 'none';
+    annotationPointerEvents = () => (this.props.isContentActive() && (this._isAnnotating || SnappingManager.GetIsDragging() || Doc.ActiveTool !== InkTool.None) ? 'all' : 'none');
     render() {
         const previewScale = this._previewNativeWidth ? 1 - this.sidebarWidth() / this._previewNativeWidth : 1;
         const pointerEvents = this.layoutDoc._lockedPosition ? 'none' : (this.props.pointerEvents?.() as any);
@@ -1013,7 +1015,11 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
             <div
                 className="webBox"
                 ref={this._mainCont}
-                style={{ pointerEvents: this.pointerEvents(), position: SnappingManager.GetIsDragging() ? 'absolute' : undefined, display: !SnappingManager.GetIsDragging() && this.props.thumbShown?.() ? 'none' : undefined }}>
+                style={{
+                    pointerEvents: this.pointerEvents(), //
+                    position: SnappingManager.GetIsDragging() ? 'absolute' : undefined,
+                    display: !this.props.isContentActive() && this.props.thumbShown?.() ? 'none' : undefined,
+                }}>
                 <div className="webBox-background" style={{ backgroundColor: this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor) }} />
                 <div
                     className="webBox-container"
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 079129dc9..2cd3c6cd6 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -297,7 +297,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
     };
 
     dispatchTransaction = (tx: Transaction) => {
-        if (this._editorView) {
+        if (this._editorView && (this._editorView as any).docView) {
             const state = this._editorView.state.apply(tx);
             this._editorView.updateState(state);
 
@@ -2020,17 +2020,15 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
     _oldWheel: any;
     render() {
         TraceMobx();
-        const active = this.props.isContentActive() || this.props.isSelected();
-        const selected = active;
+        const active = this.props.isContentActive();
         const scale = (this.props.NativeDimScaling?.() || 1) * NumCast(this.layoutDoc._freeform_scale, 1);
         const rounded = StrCast(this.layoutDoc.layout_borderRounding) === '100%' ? '-rounded' : '';
-        const interactive = (Doc.ActiveTool === InkTool.None || SnappingManager.GetIsDragging()) && (this.layoutDoc.z || !this.layoutDoc._lockedPosition);
-        if (!selected && FormattedTextBoxComment.textBox === this) setTimeout(FormattedTextBoxComment.Hide);
+        if (!active && FormattedTextBoxComment.textBox === this) setTimeout(FormattedTextBoxComment.Hide);
         const minimal = this.props.ignoreAutoHeight;
         const paddingX = NumCast(this.layoutDoc._xMargin, this.props.xPadding || 0);
         const paddingY = NumCast(this.layoutDoc._yMargin, this.props.yPadding || 0);
-        const selPad = (selected && !this.layoutDoc._createDocOnCR) || minimal ? Math.min(paddingY, Math.min(paddingX, 10)) : 0;
-        const selPaddingClass = selected && !this.layoutDoc._createDocOnCR && paddingY >= 10 ? '-selected' : '';
+        const selPad = (active && !this.layoutDoc._createDocOnCR) || minimal ? Math.min(paddingY, Math.min(paddingX, 10)) : 0;
+        const selPaddingClass = active && !this.layoutDoc._createDocOnCR && paddingY >= 10 ? '-selected' : '';
         const styleFromLayoutString = Doc.styleFromLayoutString(this.rootDoc, this.layoutDoc, this.props, scale); // this converts any expressions in the format string to style props.  e.g., <FormattedTextBox height='{this._headerHeight}px' >
         return styleFromLayoutString?.height === '0px' ? null : (
             <div
@@ -2051,7 +2049,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                               width: `${100 / scale}%`,
                               height: `${100 / scale}%`,
                           }),
-                    display: !SnappingManager.GetIsDragging() && this.props.thumbShown?.() ? 'none' : undefined,
+                    display: !this.props.isContentActive() && this.props.thumbShown?.() ? 'none' : undefined,
                     transition: 'inherit',
                     // overflowY: this.layoutDoc._layout_autoHeight ? "hidden" : undefined,
                     color: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Color),
@@ -2066,7 +2064,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                     style={{
                         overflow: this.layout_autoHeight && this.props.CollectionFreeFormDocumentView?.() ? 'hidden' : undefined, //x this breaks viewing an layout_autoHeight doc in its own tab, or in the lightbox
                         height: this.props.height || (this.layout_autoHeight && this.props.renderDepth && !this.props.suppressSetHeight ? 'max-content' : undefined),
-                        pointerEvents: interactive ? undefined : 'none',
+                        pointerEvents: Doc.ActiveTool === InkTool.None ? undefined : 'none',
                     }}
                     onContextMenu={this.specificContextMenu}
                     onKeyDown={this.onKeyDown}
@@ -2078,11 +2076,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                     onPointerDown={this.onPointerDown}
                     onDoubleClick={this.onDoubleClick}>
                     <div
-                        className={`formattedTextBox-outer${selected ? '-selected' : ''}`}
+                        className={`formattedTextBox-outer${active ? '-selected' : ''}`}
                         ref={this._scrollRef}
                         style={{
                             width: this.props.dontSelectOnLoad ? '100%' : `calc(100% - ${this.layout_sidebarWidthPercent})`,
-                            pointerEvents: !active && !SnappingManager.GetIsDragging() ? 'none' : undefined,
                             overflow: this.layoutDoc._createDocOnCR ? 'hidden' : this.layoutDoc._layout_autoHeight ? 'visible' : undefined,
                         }}
                         onScroll={this.onScroll}
@@ -2096,7 +2093,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                                 paddingRight: StrCast(this.layoutDoc._textBoxPaddingX, `${paddingX - selPad}px`),
                                 paddingTop: StrCast(this.layoutDoc._textBoxPaddingY, `${paddingY - selPad}px`),
                                 paddingBottom: StrCast(this.layoutDoc._textBoxPaddingY, `${paddingY - selPad}px`),
-                                pointerEvents: !active && !SnappingManager.GetIsDragging() ? (IsFollowLinkScript(this.layoutDoc.onClick) ? 'none' : undefined) : undefined,
+                                // pointerEvents: !active && IsFollowLinkScript(this.layoutDoc.onClick) ? 'none' : undefined,
                             }}
                         />
                     </div>
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index 4f7d2e1c1..ef1c3911c 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -1029,9 +1029,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
     removeDocument = (doc: Doc) => Doc.RemoveDocFromList(this.rootDoc, this.fieldKey, doc);
     getTransform = () => this.props.ScreenToLocalTransform().translate(-5, -65); // listBox padding-left and pres-box-cont minHeight
     panelHeight = () => this.props.PanelHeight() - 40;
-    isContentActive = (outsideReaction?: boolean) => this.props.isContentActive(outsideReaction);
-    //.ActiveTool === InkTool.None && !this.layoutDoc._lockedPosition && (this.layoutDoc.forceActive || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false;
-
     /**
      * For sorting the array so that the order is maintained when it is dropped.
      */
@@ -2462,6 +2459,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
                                 childIgnoreNativeSize={true}
                                 moveDocument={returnFalse}
                                 ignoreUnrendered={true}
+                                childDragAction="move"
                                 //childLayoutFitWidth={returnTrue}
                                 childOpacity={returnOne}
                                 childClickScript={PresBox.navigateToDocScript}
diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx
index 34e069046..f31cf6147 100644
--- a/src/client/views/nodes/trails/PresElementBox.tsx
+++ b/src/client/views/nodes/trails/PresElementBox.tsx
@@ -192,13 +192,14 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
         const dragArray = this.presBoxView?._dragArray ?? [];
         const dragData = new DragManager.DocumentDragData(this.presBoxView?.sortArray() ?? []);
         if (!dragData.draggedDocuments.length) dragData.draggedDocuments.push(this.rootDoc);
-        dragData.dropAction = 'move';
         dragData.treeViewDoc = this.presBox?._type_collection === CollectionViewType.Tree ? this.presBox : undefined; // this.props.DocumentView?.()?.props.treeViewDoc;
         dragData.moveDocument = this.props.moveDocument;
         const dragItem: HTMLElement[] = [];
+        const classesToRestore = new Map<HTMLElement, string>();
         if (dragArray.length === 1) {
             const doc = this._itemRef.current || dragArray[0];
             if (doc) {
+                classesToRestore.set(doc, doc.className);
                 doc.className = miniView ? 'presItem-miniSlide' : 'presItem-slide';
                 dragItem.push(doc);
             }
@@ -212,16 +213,19 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
             dragItem.push(doc);
         }
 
-        // const dropEvent = () => runInAction(() => this._dragging = false);
         if (activeItem) {
+            runInAction(() => (this._dragging = true));
             DragManager.StartDocumentDrag(
                 dragItem.map(ele => ele),
                 dragData,
                 e.clientX,
                 e.clientY,
-                undefined
+                undefined,
+                action(() => {
+                    Array.from(classesToRestore).forEach(pair => (pair[0].className = pair[1]));
+                    this._dragging = false;
+                })
             );
-            // runInAction(() => this._dragging = true);
             return true;
         }
         return false;
@@ -536,7 +540,6 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
                             <div
                                 className="presItem-number"
                                 title="select without navigation"
-                                style={{ pointerEvents: this.presBoxView?.isContentActive() ? 'all' : undefined }}
                                 onPointerDown={e => {
                                     e.stopPropagation();
                                     if (this._itemRef.current && this._dragRef.current) {
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index dd202418b..8f6b8cd41 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -483,7 +483,10 @@ export class PDFViewer extends React.Component<IViewerProps> {
         }
     };
 
-    pointerEvents = () => (this.props.isContentActive() && this.props.pointerEvents?.() !== 'none' && !MarqueeOptionsMenu.Instance.isShown() ? 'all' : SnappingManager.GetIsDragging() ? undefined : 'none');
+    pointerEvents = () =>
+        this.props.isContentActive() && !MarqueeOptionsMenu.Instance.isShown()
+            ? 'all' //
+            : 'none';
     @computed get annotationLayer() {
         return (
             <div className="pdfViewerDash-annotationLayer" style={{ height: Doc.NativeHeight(this.props.Document), transform: `scale(${NumCast(this.props.layoutDoc._freeform_scale, 1)})` }} ref={this._annotationLayer}>
@@ -514,10 +517,10 @@ export class PDFViewer extends React.Component<IViewerProps> {
     panelWidth = () => this.props.PanelWidth() / (this.props.NativeDimScaling?.() || 1);
     panelHeight = () => this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1);
     transparentFilter = () => [...this.props.childFilters(), Utils.IsTransparentFilter()];
-    opaqueFilter = () => [...this.props.childFilters(), Utils.noDragsDocFilter, ...(DragManager.docsBeingDragged.length ? [] : [Utils.IsOpaqueFilter()])];
+    opaqueFilter = () => [...this.props.childFilters(), Utils.noDragsDocFilter, ...(DragManager.docsBeingDragged.length && this.props.isContentActive() ? [] : [Utils.IsOpaqueFilter()])];
     childStyleProvider = (doc: Doc | undefined, props: Opt<DocumentViewProps>, property: string): any => {
         if (doc instanceof Doc && property === StyleProp.PointerEvents) {
-            if (this.inlineTextAnnotations.includes(doc)) return 'none';
+            if (this.inlineTextAnnotations.includes(doc) || this.props.isContentActive() === false) return 'none';
             return 'all';
         }
         return this.props.styleProvider?.(doc, props, property);
@@ -536,8 +539,8 @@ export class PDFViewer extends React.Component<IViewerProps> {
                 NativeWidth={returnZero}
                 NativeHeight={returnZero}
                 setContentView={emptyFunction} // override setContentView to do nothing
-                pointerEvents={SnappingManager.GetIsDragging() ? returnAll : returnNone} // freeform view doesn't get events unless something is being dragged onto it.
-                childPointerEvents="all" // but freeform children need to get events to allow text editing, etc
+                pointerEvents={SnappingManager.GetIsDragging() && this.props.isContentActive() ? returnAll : returnNone} // freeform view doesn't get events unless something is being dragged onto it.
+                childPointerEvents={this.props.isContentActive() !== false ? 'all' : 'none'} // but freeform children need to get events to allow text editing, etc
                 renderDepth={this.props.renderDepth + 1}
                 isAnnotationOverlay={true}
                 fieldKey={this.props.fieldKey + '_annotations'}
@@ -549,7 +552,6 @@ export class PDFViewer extends React.Component<IViewerProps> {
                 ScreenToLocalTransform={this.overlayTransform}
                 isAnyChildContentActive={returnFalse}
                 isAnnotationOverlayScrollable={true}
-                dropAction="embed"
                 childFilters={childFilters}
                 select={emptyFunction}
                 bringToFront={emptyFunction}
@@ -558,14 +560,14 @@ export class PDFViewer extends React.Component<IViewerProps> {
         </div>
     );
     @computed get overlayTransparentAnnotations() {
-        return this.renderAnnotations(this.transparentFilter, 'multiply', DragManager.docsBeingDragged.length ? 'none' : undefined);
+        return this.renderAnnotations(this.transparentFilter, 'multiply', DragManager.docsBeingDragged.length && this.props.isContentActive() ? 'none' : undefined);
     }
     @computed get overlayOpaqueAnnotations() {
         return this.renderAnnotations(this.opaqueFilter, this.allAnnotations.some(anno => anno.mixBlendMode) ? 'hard-light' : undefined);
     }
     @computed get overlayLayer() {
         return (
-            <div style={{ pointerEvents: SnappingManager.GetIsDragging() ? 'all' : 'none' }}>
+            <div style={{ pointerEvents: this.props.isContentActive() && SnappingManager.GetIsDragging() ? 'all' : 'none' }}>
                 {this.overlayTransparentAnnotations}
                 {this.overlayOpaqueAnnotations}
             </div>
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index c674a20d2..c9f7e4114 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -776,7 +776,7 @@ export namespace Doc {
                 linkMap.set(link[Id], await Doc.makeClone(link, cloneMap, linkMap, rtfs, exclusions, pruneDocs, cloneLinks));
             }
         });
-        Doc.SetInPlace(copy, 'title', 'CLONE: ' + doc.title, true);
+        Doc.SetInPlace(copy, 'title', '>:' + doc.title, true);
         copy.cloneOf = doc;
         cloneMap.set(doc[Id], copy);
 
diff --git a/src/fields/documentSchemas.ts b/src/fields/documentSchemas.ts
index 757d507be..76b287be7 100644
--- a/src/fields/documentSchemas.ts
+++ b/src/fields/documentSchemas.ts
@@ -95,12 +95,12 @@ export const documentSchema = createSchema({
     link_displayArrow: 'boolean', // toggles directed arrows
 
     // drag drop properties
-    _stayInCollection: 'boolean', // whether document can be dropped into a different collection
+    _dragOnlyWithinContainer: 'boolean', // whether document can be dropped into a different collection
     dragFactory: Doc, // the document that serves as the "template" for the onDragStart script.  ie, to drag out copies of the dragFactory document.
-    dropAction: 'string', // override specifying what should happen when this document is dropped (can be "embed", "copy", "move")
-    targetDropAction: 'string', // allows the target of a drop event to specify the dropAction ("embed", "copy", "move") NOTE: if the document is dropped within the same collection, the dropAction is coerced to 'move'
-    childDropAction: 'string', // specify the override for what should happen when the child of a collection is dragged from it and dropped (can be "embed" or "copy")
-    removeDropProperties: listSpec('string'), // properties that should be removed from the embed/copy/etc of this document when it is dropped
+    dropAction: 'string', // override specifying what should happen when something is dropped on this document (can be "embed", "copy", "move")
+    dragAction: 'string', // override specifying what should happen when this document s dragged (can be "embed", "copy", "move")
+    childDragAction: 'string', // specify the override for what should happen when the child of a collection is dragged from it and dropped (can be "embed" or "copy")
+    dropPropertiesToRemove: listSpec('string'), // properties that should be removed from the embed/copy/etc of this document when it is dropped
 });
 
 export const collectionSchema = createSchema({
diff --git a/src/fields/util.ts b/src/fields/util.ts
index f365adf4b..e3d1abc53 100644
--- a/src/fields/util.ts
+++ b/src/fields/util.ts
@@ -7,7 +7,7 @@ import { SerializationHelper } from '../client/util/SerializationHelper';
 import { UndoManager } from '../client/util/UndoManager';
 import { returnZero } from '../Utils';
 import CursorField from './CursorField';
-import { aclLevel, Doc, DocListCast, DocListCastAsync, HierarchyMapping, ReverseHierarchyMap, updateCachedAcls } from './Doc';
+import { aclLevel, Doc, DocListCast, DocListCastAsync, HierarchyMapping, ReverseHierarchyMap, StrListCast, updateCachedAcls } from './Doc';
 import { AclAdmin, AclEdit, AclPrivate, AclSelfEdit, DocAcl, DocData, DocLayout, FieldKeys, ForceServerWrite, Height, Initializing, SelfProxy, Update, UpdatingFromServer, Width } from './DocSymbols';
 import { Id, OnUpdate, Parent, ToValue } from './FieldSymbols';
 import { List } from './List';
@@ -86,7 +86,7 @@ const _setterImpl = action(function (target: any, prop: string | symbol | number
             DocServer.registerDocWithCachedUpdate(receiver, prop as string, curValue);
         }
         !receiver[Initializing] &&
-            !receiver.dontUndo &&
+            !StrListCast(receiver.undoIgnoreFields).includes(prop.toString()) &&
             (!receiver[UpdatingFromServer] || receiver[ForceServerWrite]) &&
             UndoManager.AddEvent(
                 {
-- 
cgit v1.2.3-70-g09d2


From 1429ab79eac9aa316082f52c14c576f6b3a97111 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 23 Jun 2023 13:14:18 -0400
Subject: cleaned up more issues with pointer events/contents active.  fixed
 dragging from piles.

---
 src/client/documents/Documents.ts                  |  7 ++-
 src/client/util/UndoManager.ts                     |  3 +-
 src/client/views/DocComponent.tsx                  |  2 +-
 src/client/views/PropertiesButtons.tsx             |  1 +
 .../collections/CollectionMasonryViewFieldRow.tsx  |  9 +--
 src/client/views/collections/CollectionMenu.tsx    |  3 +-
 .../views/collections/CollectionNoteTakingView.tsx | 13 +++--
 .../collections/CollectionNoteTakingViewColumn.tsx |  1 +
 .../views/collections/CollectionPileView.tsx       |  8 +--
 .../collections/CollectionStackedTimeline.tsx      | 30 +++++-----
 .../views/collections/CollectionStackingView.tsx   | 10 +++-
 .../CollectionStackingViewFieldColumn.tsx          |  1 +
 src/client/views/collections/CollectionSubView.tsx | 18 +++---
 .../views/collections/CollectionTreeView.tsx       | 15 +++--
 src/client/views/collections/TreeView.tsx          | 23 ++++++--
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 17 +++---
 .../collections/collectionFreeForm/MarqueeView.tsx |  1 +
 .../CollectionMulticolumnView.tsx                  |  1 +
 .../CollectionMultirowView.tsx                     |  1 +
 .../collectionSchema/CollectionSchemaView.tsx      |  3 +-
 src/client/views/nodes/ComparisonBox.tsx           | 11 ++--
 src/client/views/nodes/DocumentView.tsx            | 22 +++++---
 src/client/views/nodes/FunctionPlotBox.tsx         |  5 +-
 src/client/views/nodes/ImageBox.tsx                | 17 +++---
 src/client/views/nodes/LabelBox.tsx                |  2 +
 src/client/views/nodes/ScriptingBox.tsx            |  8 ++-
 .../views/nodes/formattedText/FormattedTextBox.tsx | 64 +++++++++++++---------
 src/fields/Proxy.ts                                |  4 +-
 src/fields/util.ts                                 |  3 +-
 29 files changed, 184 insertions(+), 119 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index a61ef1da3..acd323eca 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -361,12 +361,13 @@ export class DocumentOptions {
     _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.');
-    childDragAction?: DROPt = new DAInfo('what should happen to the child documents when they are dragged fromt he collection');
+    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");
     _dropAction?: DROPt = new DAInfo("what should happen to this document when it's dropped somewhere else");
     _dropPropertiesToRemove?: List<string>; // list of properties that should be removed from a document when it is dropped.  e.g., a creator button may be forceActive to allow it be dragged, but the forceActive property can be removed from the dropped document
     cloneFieldFilter?: List<string>; // fields not to copy when the document is clonedclipboard?: Doc;
+    dragWhenActive?: BOOLt = new BoolInfo('should document drag when it is active - e.g., pileView, group');
     dragAction?: DROPt = new DAInfo('how to drag document when it is active (e.g., tree, groups)');
     dragFactory_count?: NUMt = new NumInfo('number of items created from a drag button (used for setting title with incrementing index)', true);
     dragFactory?: Doc; // document to create when dragging with a suitable onDragStart script
@@ -667,7 +668,7 @@ export namespace Docs {
                 {
                     data: new List<Doc>(),
                     layout: { view: EmptyBox, dataField: defaultDataKey },
-                    options: { childDragAction: 'embed', title: 'Global Group Database' },
+                    options: { title: 'Global Group Database' },
                 },
             ],
             [
@@ -1663,7 +1664,7 @@ export namespace DocUtils {
             });
         });
         if (create) {
-            const newCollection = Docs.Create.PileDocument(docList, { title: 'pileup', x: (x || 0) - size, y: (y || 0) - size, _width: size * 2, _height: size * 2 });
+            const newCollection = Docs.Create.PileDocument(docList, { title: 'pileup', x: (x || 0) - size, y: (y || 0) - size, _width: size * 2, _height: size * 2, dragWhenActive: true });
             newCollection.x = NumCast(newCollection.x) + NumCast(newCollection._width) / 2 - size;
             newCollection.y = NumCast(newCollection.y) + NumCast(newCollection._height) / 2 - size;
             newCollection._width = newCollection._height = size * 2;
diff --git a/src/client/util/UndoManager.ts b/src/client/util/UndoManager.ts
index 2379cb2ab..b59af6656 100644
--- a/src/client/util/UndoManager.ts
+++ b/src/client/util/UndoManager.ts
@@ -1,4 +1,5 @@
 import { observable, action, runInAction } from 'mobx';
+import { Field } from '../../fields/Doc';
 import { Without } from '../../Utils';
 
 function getBatchName(target: any, key: string | symbol): string {
@@ -95,7 +96,7 @@ export namespace UndoManager {
 
     export function AddEvent(event: UndoEvent, value?: any): void {
         if (currentBatch && batchCounter.get() && !undoing) {
-            console.log('                         '.slice(0, batchCounter.get()) + 'UndoEvent : ' + event.prop + ' = ' + value);
+            console.log('                         '.slice(0, batchCounter.get()) + 'UndoEvent : ' + event.prop + ' = ' + (value instanceof Array ? value.map(val => Field.toScriptString(val)).join(',') : Field.toScriptString(value)));
             currentBatch.push(event);
             tempEvents?.push(event);
         }
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index 0709d6cb9..3de40a640 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -220,7 +220,7 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps>()
                             Doc.ActiveDashboard && inheritParentAcls(Doc.ActiveDashboard, doc);
                         });
                     const annoDocs = targetDataDoc[annotationKey ?? this.annotationKey] as List<Doc>;
-                    if (annoDocs instanceof List) annoDocs.push(...added);
+                    if (annoDocs instanceof List) annoDocs.push(...added.filter(add => !annoDocs.includes(add)));
                     else targetDataDoc[annotationKey ?? this.annotationKey] = new List<Doc>(added);
                     targetDataDoc[(annotationKey ?? this.annotationKey) + '_modificationDate'] = new DateField(new Date(Date.now()));
                 }
diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx
index 11b89fd69..74dd1c2f7 100644
--- a/src/client/views/PropertiesButtons.tsx
+++ b/src/client/views/PropertiesButtons.tsx
@@ -209,6 +209,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
             (dv, doc) => {
                 doc.isGroup = !doc.isGroup;
                 doc.forceActive = doc.isGroup;
+                doc.dragWhenActive = doc.isGroup;
             }
         );
     }
diff --git a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
index 64f9c6a87..6f88f6727 100644
--- a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
+++ b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
@@ -98,14 +98,15 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
     rowDrop = action((e: Event, de: DragManager.DropEvent) => {
         this._createEmbeddingSelected = false;
         if (de.complete.docDragData) {
-            this.props.parent.Document.dropConverter instanceof ScriptField && this.props.parent.Document.dropConverter.script.run({ dragData: de.complete.docDragData });
             const key = this.props.pivotField;
             const castedValue = this.getValue(this.heading);
             const onLayoutDoc = this.onLayoutDoc(key);
-            de.complete.docDragData.droppedDocuments.forEach(d => Doc.SetInPlace(d, key, castedValue, !onLayoutDoc));
-            this.props.parent.onInternalDrop(e, de);
-            e.stopPropagation();
+            if (this.props.parent.onInternalDrop(e, de)) {
+                de.complete.docDragData.droppedDocuments.forEach(d => Doc.SetInPlace(d, key, castedValue, !onLayoutDoc));
+            }
+            return true;
         }
+        return false;
     });
 
     getValue = (value: string): any => {
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index fc3f713ce..7d71bce13 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -427,8 +427,9 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewMenu
         if (docDragData?.draggedDocuments.length) {
             this._buttonizableCommands?.filter(c => c.title === this._currentKey).map(c => c.immediate(docDragData.draggedDocuments || []));
             e.stopPropagation();
+            return true;
         }
-        return true;
+        return false;
     }
 
     dragViewDown = (e: React.PointerEvent) => {
diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx
index 9a3ab8074..f1c4c2cdf 100644
--- a/src/client/views/collections/CollectionNoteTakingView.tsx
+++ b/src/client/views/collections/CollectionNoteTakingView.tsx
@@ -441,23 +441,24 @@ export class CollectionNoteTakingView extends CollectionSubView() {
                         docs.splice(previousDocIndex + 1, 0, ...newDocs);
                     }
                 }
+                return true;
             }
         } else if (de.complete.linkDragData?.dragDocument.embedContainer === this.props.Document && de.complete.linkDragData?.linkDragView?.props.CollectionFreeFormDocumentView?.()) {
             const source = Docs.Create.TextDocument('', { _width: 200, _height: 75, _layout_fitWidth: true, title: 'dropped annotation' });
-            this.props.addDocument?.(source);
+            if (!this.props.addDocument?.(source)) e.preventDefault();
             de.complete.linkDocument = DocUtils.MakeLink(source, de.complete.linkDragData.linkSourceGetAnchor(), { link_relationship: 'doc annotation' }); // TODODO this is where in text links get passed
             e.stopPropagation();
-        } else if (de.complete.annoDragData?.dragDocument && super.onInternalDrop(e, de)) return this.internalAnchorAnnoDrop(e, de.complete.annoDragData);
+            return true;
+        } else if (de.complete.annoDragData?.dragDocument && super.onInternalDrop(e, de)) {
+            return this.internalAnchorAnnoDrop(e, de.complete.annoDragData);
+        }
         return false;
     };
 
     @undoBatch
     internalAnchorAnnoDrop(e: Event, annoDragData: DragManager.AnchorAnnoDragData) {
         const dropCreator = annoDragData.dropDocCreator;
-        annoDragData.dropDocCreator = (annotationOn: Doc | undefined) => {
-            const dropDoc = dropCreator(annotationOn);
-            return dropDoc || this.rootDoc;
-        };
+        annoDragData.dropDocCreator = (annotationOn: Doc | undefined) => dropCreator(annotationOn) || this.rootDoc;
         return true;
     }
 
diff --git a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx
index 2f28ecd00..3286d60bd 100644
--- a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx
+++ b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx
@@ -92,6 +92,7 @@ export class CollectionNoteTakingViewColumn extends React.Component<CSVFieldColu
     columnDrop = action((e: Event, de: DragManager.DropEvent) => {
         const drop = { docs: de.complete.docDragData?.droppedDocuments, val: this.getValue(this._heading) };
         drop.docs?.forEach(d => Doc.SetInPlace(d, this.props.pivotField, drop.val, false));
+        return true;
     });
 
     getValue = (value: string): any => {
diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx
index 15570b195..91be31289 100644
--- a/src/client/views/collections/CollectionPileView.tsx
+++ b/src/client/views/collections/CollectionPileView.tsx
@@ -63,12 +63,14 @@ export class CollectionPileView extends CollectionSubView() {
             <div className="collectionPileView-innards" style={{ pointerEvents: this.contentEvents }}>
                 <CollectionFreeFormView
                     {...this.props} //
-                    childContentsActive={returnFalse}
                     layoutEngine={this.layoutEngine}
                     addDocument={this.addPileDoc}
+                    moveDocument={this.removePileDoc}
+                    // pile children never have their contents active, but will be document active whenever the entire pile is.
+                    childContentsActive={returnFalse}
+                    childDocumentsActive={this.props.isDocumentActive}
                     childDragAction="move"
                     childClickScript={this.toggleIcon}
-                    moveDocument={this.removePileDoc}
                 />
             </div>
         );
@@ -106,7 +108,6 @@ export class CollectionPileView extends CollectionSubView() {
     _undoBatch: UndoManager.Batch | undefined;
     pointerDown = (e: React.PointerEvent) => {
         let dist = 0;
-        SnappingManager.SetIsDragging(true);
         setupMoveUpEvents(
             this,
             e,
@@ -129,7 +130,6 @@ export class CollectionPileView extends CollectionSubView() {
             () => {
                 this._undoBatch?.end();
                 this._undoBatch = undefined;
-                SnappingManager.SetIsDragging(false);
             },
             emptyFunction,
             e.shiftKey && this.layoutEngine() === computePassLayout.name,
diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index e835fa659..ad84d859d 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -369,22 +369,22 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
     // handles dragging and dropping markers in timeline
     @action
     internalDocDrop(e: Event, de: DragManager.DropEvent, docDragData: DragManager.DocumentDragData, xp: number) {
-        if (!de.embedKey && this.props.Document._isGroup) return false;
-        if (!super.onInternalDrop(e, de)) return false;
-
-        // determine x coordinate of drop and assign it to the documents being dragged  --- see internalDocDrop of collectionFreeFormView.tsx for how it's done when dropping onto a 2D freeform view
-        const localPt = this.props.ScreenToLocalTransform().transformPoint(de.x, de.y);
-        const x = localPt[0] - docDragData.offset[0];
-        const timelinePt = this.toTimeline(x + this._scroll, this.timelineContentWidth);
-        docDragData.droppedDocuments.forEach(drop => {
-            const anchorEnd = this.anchorEnd(drop);
-            if (anchorEnd !== undefined) {
-                Doc.SetInPlace(drop, drop._timecodeToHide === undefined ? this.props.endTag : 'timecodeToHide', timelinePt + anchorEnd - this.anchorStart(drop), false);
-            }
-            Doc.SetInPlace(drop, drop._timecodeToShow === undefined ? this.props.startTag : 'timecodeToShow', timelinePt, false);
-        });
+        if (super.onInternalDrop(e, de)) {
+            // determine x coordinate of drop and assign it to the documents being dragged  --- see internalDocDrop of collectionFreeFormView.tsx for how it's done when dropping onto a 2D freeform view
+            const localPt = this.props.ScreenToLocalTransform().transformPoint(de.x, de.y);
+            const x = localPt[0] - docDragData.offset[0];
+            const timelinePt = this.toTimeline(x + this._scroll, this.timelineContentWidth);
+            docDragData.droppedDocuments.forEach(drop => {
+                const anchorEnd = this.anchorEnd(drop);
+                if (anchorEnd !== undefined) {
+                    Doc.SetInPlace(drop, drop._timecodeToHide === undefined ? this.props.endTag : 'timecodeToHide', timelinePt + anchorEnd - this.anchorStart(drop), false);
+                }
+                Doc.SetInPlace(drop, drop._timecodeToShow === undefined ? this.props.startTag : 'timecodeToShow', timelinePt, false);
+            });
 
-        return true;
+            return true;
+        }
+        return false;
     }
 
     onInternalDrop = (e: Event, de: DragManager.DropEvent) => {
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 8eed4f716..4756b4cd3 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -459,18 +459,24 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
                 const docs = this.childDocList;
                 // still figuring out where to add the document
                 if (docs && newDocs.length) {
+                    newDocs.forEach(newdoc => docs.indexOf(newdoc) !== -1 && docs.splice(docs.indexOf(newdoc), 1));
                     const insertInd = dropInd === -1 ? docs.length : dropInd + dropAfter;
                     const offset = newDocs.reduce((off, ndoc) => (this.filteredChildren.find((fdoc, i) => ndoc === fdoc && i < insertInd) ? off + 1 : off), 0);
                     newDocs.filter(ndoc => docs.indexOf(ndoc) !== -1).forEach(ndoc => docs.splice(docs.indexOf(ndoc), 1));
                     docs.splice(insertInd - offset, 0, ...newDocs);
                 }
+                return true;
             }
         } else if (de.complete.linkDragData?.dragDocument.embedContainer === this.props.Document && de.complete.linkDragData?.linkDragView?.props.CollectionFreeFormDocumentView?.()) {
             const source = Docs.Create.TextDocument('', { _width: 200, _height: 75, _layout_fitWidth: true, title: 'dropped annotation' });
-            this.props.addDocument?.(source);
+            if (!this.props.addDocument?.(source)) e.preventDefault();
             de.complete.linkDocument = DocUtils.MakeLink(source, de.complete.linkDragData.linkSourceGetAnchor(), { link_relationship: 'doc annotation' }); // TODODO this is where in text links get passed
             e.stopPropagation();
-        } else if (de.complete.annoDragData?.dragDocument && super.onInternalDrop(e, de)) return this.internalAnchorAnnoDrop(e, de.complete.annoDragData);
+            return true;
+        } else if (de.complete.annoDragData?.dragDocument && super.onInternalDrop(e, de)) {
+            return this.internalAnchorAnnoDrop(e, de.complete.annoDragData);
+        }
+        e.preventDefault();
         return false;
     };
 
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index 6be9cb72d..ebb4ba5a1 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -94,6 +94,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
     columnDrop = action((e: Event, de: DragManager.DropEvent) => {
         const drop = { docs: de.complete.docDragData?.droppedDocuments, val: this.getValue(this._heading) };
         this.props.pivotField && drop.docs?.forEach(d => Doc.SetInPlace(d, this.props.pivotField, drop.val, false));
+        return true;
     });
     getValue = (value: string): any => {
         const parsed = parseInt(value);
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 539dde7e0..39fb2db1e 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -185,12 +185,14 @@ export function CollectionSubView<X>(moreProps?: X) {
         @undoBatch
         protected onGesture(e: Event, ge: GestureUtils.GestureEvent) {}
 
-        protected onInternalPreDrop(e: Event, de: DragManager.DropEvent, targetAction: dropActionType) {
+        protected onInternalPreDrop(e: Event, de: DragManager.DropEvent) {
             if (de.complete.docDragData) {
-                // if dropAction is, say 'embed', but we're just dragging within a collection, we want to ignore the targetAction.
-                // otherwise, the targetAction should become the actual action (which can still be overridden by the userDropAction -eg, shift/ctrl keys)
-                if (targetAction && !de.complete.docDragData.draggedDocuments.some(d => d.embedContainer === this.props.Document && this.childDocs.includes(d))) {
-                    de.complete.docDragData.dropAction = targetAction;
+                // override the dropEvent's dropAction
+                const dropAction = this.layoutDoc.dropAction as dropActionType;
+                // if the dropEvent's dragAction is, say 'embed', but we're just dragging within a collection, we may not actually want to make an embedding.
+                // so we check if our collection has a dropAction set on it and if so, we use that instead.
+                if (dropAction && !de.complete.docDragData.draggedDocuments.some(d => d.embedContainer === this.props.Document && this.childDocs.includes(d))) {
+                    de.complete.docDragData.dropAction = dropAction;
                 }
                 e.stopPropagation();
             }
@@ -218,16 +220,16 @@ export function CollectionSubView<X>(moreProps?: X) {
                         ScriptCast(this.rootDoc.dropConverter)?.script.run({ dragData: docDragData });
                         added = addedDocs.length ? this.addDocument(addedDocs) : true;
                     }
-                    added && e.stopPropagation();
-                    return added;
                 } else {
                     ScriptCast(this.rootDoc.dropConverter)?.script.run({ dragData: docDragData });
                     added = this.addDocument(docDragData.droppedDocuments);
+                    !added && alert('You cannot perform this move');
                 }
-                !added && alert('You cannot perform this move');
+                !added && e.preventDefault();
                 e.stopPropagation();
                 return added;
             } else if (de.complete.annoDragData) {
+                e.stopPropagation();
                 const dropCreator = de.complete.annoDragData.dropDocCreator;
                 de.complete.annoDragData.dropDocCreator = () => {
                     const dropped = dropCreator(this.props.isAnnotationOverlay ? this.rootDoc : undefined);
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 7598bb753..4cd3885f5 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -140,11 +140,16 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
         if ((this._mainEle = ele)) this._treedropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.doc, this.onInternalPreDrop.bind(this));
     };
 
-    protected onInternalPreDrop = (e: Event, de: DragManager.DropEvent, targetAction: dropActionType) => {
+    protected onInternalPreDrop = (e: Event, de: DragManager.DropEvent) => {
+        const dropAction = this.layoutDoc.dropAction as dropActionType;
         const dragData = de.complete.docDragData;
         if (dragData) {
-            const isInTree = () => Doc.AreProtosEqual(dragData.treeViewDoc, this.props.Document) || dragData.draggedDocuments.some(d => d.embedContainer === this.doc && this.childDocs.includes(d));
-            dragData.dropAction = targetAction && !isInTree() ? targetAction : this.doc === dragData?.treeViewDoc ? 'same' : dragData.dropAction;
+            const sameTree = Doc.AreProtosEqual(dragData.treeViewDoc, this.rootDoc) ? true : false;
+            const isAlreadyInTree = () => sameTree || dragData.draggedDocuments.some(d => d.embedContainer === this.doc && this.childDocs.includes(d));
+            if (isAlreadyInTree() !== sameTree) {
+                console.log('WHAAAT');
+            }
+            dragData.dropAction = dropAction && !isAlreadyInTree() ? dropAction : sameTree ? 'same' : dragData.dropAction;
         }
     };
 
@@ -394,6 +399,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
                 <div
                     className="collectionTreeView-contents"
                     key="tree"
+                    ref={r => !this.doc.treeViewHasOverlay && r && this.createTreeDropTarget(r)}
                     style={{
                         ...(!titleBar ? { marginLeft: this.marginX(), paddingTop: this.marginTop() } : {}),
                         overflow: 'auto',
@@ -417,8 +423,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
                                 minHeight: '100%',
                             }}
                             onWheel={e => e.stopPropagation()}
-                            onDrop={this.onTreeDrop}
-                            ref={r => !this.doc.treeViewHasOverlay && r && this.createTreeDropTarget(r)}>
+                            onDrop={this.onTreeDrop}>
                             <ul className={`no-indent${this.outlineMode ? '-outline' : ''}`}>{this.treeViewElements}</ul>
                         </div>
                     </div>
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 91ae2b3cc..8d8d895c6 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -347,7 +347,7 @@ export class TreeView extends React.Component<TreeViewProps> {
     };
     deleteItem = () => this.props.removeDoc?.(this.doc);
 
-    preTreeDrop = (e: Event, de: DragManager.DropEvent, targetAction: dropActionType) => {
+    preTreeDrop = (e: Event, de: DragManager.DropEvent) => {
         const dragData = de.complete.docDragData;
         dragData && (dragData.dropAction = this.props.treeView.props.Document === dragData.treeViewDoc ? 'same' : dragData.dropAction);
     };
@@ -355,7 +355,7 @@ export class TreeView extends React.Component<TreeViewProps> {
     @undoBatch
     treeDrop = (e: Event, de: DragManager.DropEvent) => {
         const pt = [de.x, de.y];
-        if (!this._header.current) return;
+        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);
@@ -364,14 +364,25 @@ export class TreeView extends React.Component<TreeViewProps> {
             const destDoc = this.doc;
             DocUtils.MakeLink(sourceDoc, destDoc, { link_relationship: 'tree link' });
             e.stopPropagation();
+            return true;
         }
         const docDragData = de.complete.docDragData;
         if (docDragData && pt[0] < rect.left + rect.width) {
             if (docDragData.draggedDocuments[0] === this.doc) return true;
-            if (this.dropDocuments(docDragData.droppedDocuments, before, inside, docDragData.dropAction, docDragData.removeDocument, docDragData.moveDocument, docDragData.treeViewDoc === this.props.treeView.props.Document)) {
-                e.stopPropagation();
-            }
+            const added = this.dropDocuments(
+                docDragData.droppedDocuments, //
+                before,
+                inside,
+                docDragData.dropAction,
+                docDragData.removeDocument,
+                docDragData.moveDocument,
+                docDragData.treeViewDoc === this.props.treeView.props.Document
+            );
+            e.stopPropagation();
+            !added && e.preventDefault();
+            return added;
         }
+        return false;
     };
 
     dropping: boolean = false;
@@ -924,7 +935,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                 PanelHeight={return18}
                 contextMenuItems={this.contextMenuItems}
                 renderDepth={1}
-                isContentActive={this.props.isContentActive}
+                isContentActive={emptyFunction} //this.props.isContentActive}
                 isDocumentActive={this.props.isContentActive}
                 focus={this.refocus}
                 whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index d7e073c5f..e6f8f3071 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -418,15 +418,16 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     @undoBatch
     internalLinkDrop(e: Event, de: DragManager.DropEvent, linkDragData: DragManager.LinkDragData, xp: number, yp: number) {
         if (linkDragData.linkDragView.props.docViewPath().includes(this.props.docViewPath().lastElement())) {
-            // dragged document is a child of this collection
-            if (!linkDragData.linkDragView.props.CollectionFreeFormDocumentView?.() || linkDragData.dragDocument.embedContainer !== this.props.Document) {
-                // if the source doc view's embedContainer isn't this same freeformcollectionlinkDragData.dragDocument.embedContainer === this.props.Document
+            let added = false;
+            //  do nothing if link is dropped into any freeform view parent of dragged document
+            if (!linkDragData.dragDocument.embedContainer || linkDragData.dragDocument.embedContainer !== this.rootDoc) {
                 const source = Docs.Create.TextDocument('', { _width: 200, _height: 75, x: xp, y: yp, title: 'dropped annotation' });
-                this.props.addDocument?.(source);
+                added = this.props.addDocument?.(source) ? true : false;
                 de.complete.linkDocument = DocUtils.MakeLink(linkDragData.linkSourceGetAnchor(), source, { link_relationship: 'annotated by:annotation of' }); // TODODO this is where in text links get passed
             }
-            e.stopPropagation(); //  do nothing if link is dropped into any freeform view parent of dragged document
-            return true;
+            e.stopPropagation();
+            !added && e.preventDefault();
+            return added;
         }
         return false;
     }
@@ -1297,8 +1298,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 childFilters={this.childDocFilters}
                 childFiltersByRanges={this.childDocRangeFilters}
                 searchFilterDocs={this.searchFilterDocs}
-                isDocumentActive={this.props.childDocumentsActive?.() ? this.props.isDocumentActive : this.isContentActive}
-                isContentActive={this.props.childContentsActive ?? this.props.isContentActive() === false ? returnFalse : emptyFunction}
+                isDocumentActive={this.props.childDocumentsActive?.() || this.rootDoc._isGroup ? this.props.isDocumentActive : this.isContentActive}
+                isContentActive={this.props.childContentsActive ?? this.isContentActive() === false ? returnFalse : emptyFunction}
                 focus={this.Document._isGroup ? this.groupFocus : this.isAnnotationOverlay ? this.props.focus : this.focus}
                 addDocTab={this.addDocTab}
                 addDocument={this.props.addDocument}
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 898452ccb..5febbe83e 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -385,6 +385,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
         newCollection._width = this.Bounds.width;
         newCollection._height = this.Bounds.height;
         newCollection._isGroup = makeGroup;
+        newCollection._dragWhenActive = makeGroup;
         newCollection.forceActive = makeGroup;
         newCollection.x = this.Bounds.left;
         newCollection.y = this.Bounds.top;
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index 32b42223b..6dcd2d422 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -220,6 +220,7 @@ export class CollectionMulticolumnView extends CollectionSubView() {
                         }
                     })
                 );
+                return true;
             }
         }
         return false;
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index fa3a9f352..4df5dad5a 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -220,6 +220,7 @@ export class CollectionMultirowView extends CollectionSubView() {
                         }
                     })
                 );
+                return true;
             }
         }
         return false;
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 06b227b4b..ee5bf82ed 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -434,7 +434,6 @@ export class CollectionSchemaView extends CollectionSubView() {
     @action
     onInternalDrop = (e: Event, de: DragManager.DropEvent) => {
         if (de.complete.columnDragData) {
-            e.stopPropagation();
             const mouseX = this.props.ScreenToLocalTransform().transformPoint(de.x, de.y)[0];
             const index = this.findDropIndex(mouseX);
             this.moveColumn(de.complete.columnDragData.colIndex, index ?? de.complete.columnDragData.colIndex);
@@ -448,6 +447,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                 });
             });
 
+            e.stopPropagation();
             return true;
         }
         const draggedDocs = de.complete.docDragData?.draggedDocuments;
@@ -462,7 +462,6 @@ export class CollectionSchemaView extends CollectionSubView() {
                 if (draggedView) DocumentManager.Instance.RemoveView(draggedView);
                 DocumentManager.Instance.AddViewRenderedCb(doc, dv => dv.select(true));
             });
-            e.stopPropagation();
             return true;
         }
         return false;
diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx
index d747c4527..2290e0711 100644
--- a/src/client/views/nodes/ComparisonBox.tsx
+++ b/src/client/views/nodes/ComparisonBox.tsx
@@ -42,13 +42,14 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
     };
 
     @undoBatch
-    private internalDrop = (event: Event, dropEvent: DragManager.DropEvent, fieldKey: string) => {
+    private internalDrop = (e: Event, dropEvent: DragManager.DropEvent, fieldKey: string) => {
         if (dropEvent.complete.docDragData) {
-            event.stopPropagation(); // prevent parent Doc from registering new position so that it snaps back into place
             const droppedDocs = dropEvent.complete.docDragData?.droppedDocuments;
-            const res = dropEvent.complete.docDragData.moveDocument?.(droppedDocs, this.rootDoc, (doc: Doc | Doc[]) => this.addDoc(doc instanceof Doc ? doc : doc.lastElement(), fieldKey));
-            res && (droppedDocs.lastElement().embedContainer = this.dataDoc);
-            return res;
+            const added = dropEvent.complete.docDragData.moveDocument?.(droppedDocs, this.rootDoc, (doc: Doc | Doc[]) => this.addDoc(doc instanceof Doc ? doc : doc.lastElement(), fieldKey));
+            droppedDocs.lastElement().embedContainer = this.dataDoc;
+            !added && e.preventDefault();
+            e.stopPropagation(); // prevent parent Doc from registering new position so that it snaps back into place
+            return added;
         }
     };
 
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index fbc84389d..b6f1626f8 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -356,9 +356,10 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     componentDidMount() {
         this.setupHandlers();
     }
-    preDropFunc = (e: Event, de: DragManager.DropEvent, targetAction: dropActionType) => {
-        if (de.complete.docDragData && this.isContentActive()) {
-            targetAction && (de.complete.docDragData.dropAction = targetAction);
+    preDropFunc = (e: Event, de: DragManager.DropEvent) => {
+        const dropAction = this.layoutDoc.dropAction as dropActionType;
+        if (de.complete.docDragData && this.isContentActive() && !this.props.treeViewDoc) {
+            dropAction && (de.complete.docDragData.dropAction = dropAction);
             e.stopPropagation();
         }
     };
@@ -492,8 +493,13 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                     }
                     preventDefault = false;
                 }
-
-                this._singleClickFunc = clickFunc ?? (() => this._componentView?.select?.(e.ctrlKey || e.metaKey, e.shiftKey) ?? this.props.select(e.ctrlKey || e.metaKey || e.shiftKey));
+                const sendToBack = e.altKey;
+                this._singleClickFunc =
+                    clickFunc ??
+                    (() =>
+                        sendToBack
+                            ? this.props.DocumentView().props.CollectionFreeFormDocumentView?.().props.bringToFront(this.rootDoc, true)
+                            : this._componentView?.select?.(e.ctrlKey || e.metaKey, e.shiftKey) ?? this.props.select(e.ctrlKey || e.metaKey || e.shiftKey));
                 const waitFordblclick = this.props.waitForDoubleClickToClick?.() ?? this.Document.waitForDoubleClickToClick;
                 if ((clickFunc && waitFordblclick !== 'never') || waitFordblclick === 'always') {
                     this._doubleClickTimeout && clearTimeout(this._doubleClickTimeout);
@@ -541,7 +547,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                 //if (this.props.isSelected(true) && this.rootDoc.type !== DocumentType.PDF && this.layoutDoc._type_collection !== CollectionViewType.Docking) e.preventDefault();
 
                 // listen to move events if document content isn't active or document is draggable
-                if (!this.layoutDoc._lockedPosition && (!this.isContentActive() || this.props.dragAction || this.rootDoc.dragAction)) {
+                if (!this.layoutDoc._lockedPosition && (!this.isContentActive() || BoolCast(this.rootDoc._dragWhenActive))) {
                     document.addEventListener('pointermove', this.onPointerMove);
                 }
             }
@@ -617,15 +623,14 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
         if (this.props.dontRegisterView || this.props.LayoutTemplateString?.includes(LinkAnchorBox.name)) return false;
         if (this.props.Document === Doc.ActiveDashboard) {
             e.stopPropagation();
-            alert((e.target as any)?.closest?.('*.lm_content') ? "You can't perform this move most likely because you don't have permission to modify the destination." : 'Linking to document tabs not yet supported. Drop link on document content.');
             e.preventDefault();
+            alert((e.target as any)?.closest?.('*.lm_content') ? "You can't perform this move most likely because you don't have permission to modify the destination." : 'Linking to document tabs not yet supported. Drop link on document content.');
             return true;
         }
         const linkdrag = de.complete.annoDragData ?? de.complete.linkDragData;
         if (linkdrag) {
             linkdrag.linkSourceDoc = linkdrag.linkSourceGetAnchor();
             if (linkdrag.linkSourceDoc) {
-                e.stopPropagation();
                 if (de.complete.annoDragData && !de.complete.annoDragData.dropDocument) {
                     de.complete.annoDragData.dropDocument = de.complete.annoDragData.dropDocCreator(undefined);
                 }
@@ -633,6 +638,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                     const dropDoc = de.complete.annoDragData?.dropDocument ?? this._componentView?.getAnchor?.(true) ?? this.rootDoc;
                     de.complete.linkDocument = DocUtils.MakeLink(linkdrag.linkSourceDoc, dropDoc, {}, undefined, [de.x, de.y - 50]);
                 }
+                e.stopPropagation();
                 return true;
             }
         }
diff --git a/src/client/views/nodes/FunctionPlotBox.tsx b/src/client/views/nodes/FunctionPlotBox.tsx
index 8a88bede6..61711417f 100644
--- a/src/client/views/nodes/FunctionPlotBox.tsx
+++ b/src/client/views/nodes/FunctionPlotBox.tsx
@@ -80,9 +80,10 @@ export class FunctionPlotBox extends ViewBoxAnnotatableComponent<FieldViewProps>
     @undoBatch
     drop = (e: Event, de: DragManager.DropEvent) => {
         if (de.complete.docDragData?.droppedDocuments.length) {
+            const added = de.complete.docDragData.droppedDocuments.reduce((res, doc) => res && Doc.AddDocToList(this.dataDoc, this.props.fieldKey, doc), true);
+            !added && e.preventDefault();
             e.stopPropagation(); // prevent parent Doc from registering new position so that it snaps back into place
-            de.complete.docDragData.droppedDocuments.map(doc => Doc.AddDocToList(this.dataDoc, this.props.fieldKey, doc));
-            return false;
+            return added;
         }
         return false;
     };
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 64d6814df..f67930a3f 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -135,19 +135,17 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
     @action
     drop = (e: Event, de: DragManager.DropEvent) => {
         if (de.complete.docDragData) {
+            let added = true;
             const targetIsBullseye = (ele: HTMLElement): boolean => {
                 if (!ele) return false;
                 if (ele === this._overlayIconRef.current) return true;
                 return targetIsBullseye(ele.parentElement as HTMLElement);
             };
             if (de.metaKey || targetIsBullseye(e.target as HTMLElement)) {
-                de.complete.docDragData.droppedDocuments.forEach(
-                    action((drop: Doc) => {
-                        Doc.AddDocToList(this.dataDoc, this.fieldKey + '-alternates', drop);
-                        this.rootDoc[this.fieldKey + '_usePath'] = 'alternate:hover';
-                        e.stopPropagation();
-                    })
-                );
+                added = de.complete.docDragData.droppedDocuments.reduce((last: boolean, drop: Doc) => {
+                    this.rootDoc[this.fieldKey + '_usePath'] = 'alternate:hover';
+                    return last && Doc.AddDocToList(this.dataDoc, this.fieldKey + '-alternates', drop);
+                }, true);
             } else if (de.altKey || !this.dataDoc[this.fieldKey]) {
                 const layoutDoc = de.complete.docDragData?.draggedDocuments[0];
                 const targetField = Doc.LayoutFieldKey(layoutDoc);
@@ -156,10 +154,13 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                     this.dataDoc[this.fieldKey] = ObjectField.MakeCopy(targetDoc[targetField] as ImageField);
                     Doc.SetNativeWidth(this.dataDoc, Doc.NativeWidth(targetDoc), this.fieldKey);
                     Doc.SetNativeHeight(this.dataDoc, Doc.NativeHeight(targetDoc), this.fieldKey);
-                    e.stopPropagation();
                 }
             }
+            !added && e.preventDefault();
+            e.stopPropagation();
+            return added;
         }
+        return false;
     };
 
     @undoBatch
diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx
index 52f3575cb..4439be0cd 100644
--- a/src/client/views/nodes/LabelBox.tsx
+++ b/src/client/views/nodes/LabelBox.tsx
@@ -74,7 +74,9 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps & LabelBoxProp
         if (docDragData && missingParams?.includes((e.target as any).textContent)) {
             this.paramsDoc[(e.target as any).textContent] = new List<Doc>(docDragData.droppedDocuments.map((d, i) => (d.onDragStart ? docDragData.draggedDocuments[i] : d)));
             e.stopPropagation();
+            return true;
         }
+        return false;
     };
 
     @observable _mouseOver = false;
diff --git a/src/client/views/nodes/ScriptingBox.tsx b/src/client/views/nodes/ScriptingBox.tsx
index 37fda14fc..3ad3c911d 100644
--- a/src/client/views/nodes/ScriptingBox.tsx
+++ b/src/client/views/nodes/ScriptingBox.tsx
@@ -270,8 +270,12 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
     // sets field of the corresponding field key (param name) to be dropped document
     @action
     onDrop = (e: Event, de: DragManager.DropEvent, fieldKey: string) => {
-        Doc.SetInPlace(this.rootDoc, fieldKey, de.complete.docDragData?.droppedDocuments[0], true);
-        e.stopPropagation();
+        if (de.complete.docDragData) {
+            de.complete.docDragData.droppedDocuments.forEach(doc => Doc.SetInPlace(this.rootDoc, fieldKey, doc, true));
+            e.stopPropagation();
+            return true;
+        }
+        return false;
     };
 
     // deletes a param from all areas in which it is stored
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 2e8f6c696..da0fc9ffb 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -531,36 +531,50 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
     @undoBatch
     @action
     drop = (e: Event, de: DragManager.DropEvent) => {
-        if (de.complete.annoDragData) de.complete.annoDragData.dropDocCreator = () => this.getAnchor(true);
+        if (de.complete.annoDragData) {
+            de.complete.annoDragData.dropDocCreator = () => this.getAnchor(true);
+            e.stopPropagation();
+            return true;
+        }
         const dragData = de.complete.docDragData;
         if (dragData) {
-            const draggedDoc = dragData.draggedDocuments.length && dragData.draggedDocuments[0];
-            // replace text contents whend dragging with Alt
-            if (draggedDoc && draggedDoc.type === DocumentType.RTF && !Doc.AreProtosEqual(draggedDoc, this.props.Document) && de.altKey) {
-                if (draggedDoc.data instanceof RichTextField) {
-                    Doc.GetProto(this.dataDoc)[this.fieldKey] = new RichTextField(draggedDoc.data.Data, draggedDoc.data.Text);
-                    e.stopPropagation();
-                }
-                // embed document when dragg marked as embed
-            } else if (de.embedKey) {
-                const target = dragData.droppedDocuments[0];
-                const node = schema.nodes.dashDoc.create({
-                    width: target[Width](),
-                    height: target[Height](),
-                    title: 'dashDoc',
-                    docId: target[Id],
-                    float: 'unset',
-                });
-                if (!['embed', 'copy'].includes((dragData.dropAction ?? '') as any)) {
-                    dragData.removeDocument?.(dragData.draggedDocuments[0]);
+            const dataDoc = Doc.IsDelegateField(DocCast(this.layoutDoc.proto), this.fieldKey) ? DocCast(this.layoutDoc.proto) : this.dataDoc;
+            const effectiveAcl = GetEffectiveAcl(dataDoc);
+            let added = [AclEdit, AclAdmin, AclSelfEdit].includes(effectiveAcl);
+            const draggedDoc = dragData.draggedDocuments.lastElement();
+            if (added) {
+                // replace text contents when dragging with Alt
+                if (de.altKey) {
+                    const fieldKey = Doc.LayoutFieldKey(draggedDoc);
+                    if (draggedDoc[fieldKey] instanceof RichTextField && !Doc.AreProtosEqual(draggedDoc, this.props.Document)) {
+                        Doc.GetProto(this.dataDoc)[this.fieldKey] = Field.Copy(draggedDoc[fieldKey]);
+                    }
+
+                    // embed document when drag marked as embed
+                } else if (de.embedKey) {
+                    const node = schema.nodes.dashDoc.create({
+                        width: draggedDoc[Width](),
+                        height: draggedDoc[Height](),
+                        title: 'dashDoc',
+                        docId: draggedDoc[Id],
+                        float: 'unset',
+                    });
+                    if (!['embed', 'copy'].includes((dragData.dropAction ?? '') as any)) {
+                        added = dragData.removeDocument?.(draggedDoc) ? true : false;
+                    }
+                    if (added) {
+                        draggedDoc._freeform_fitContentsToBox = true;
+                        draggedDoc.embedContainer = this.rootDoc;
+                        const view = this._editorView!;
+                        view.dispatch(view.state.tr.insert(view.posAtCoords({ left: de.x, top: de.y })!.pos, node));
+                    }
                 }
-                target._freeform_fitContentsToBox = true;
-                target.embedContainer = this.rootDoc;
-                const view = this._editorView!;
-                view.dispatch(view.state.tr.insert(view.posAtCoords({ left: de.x, top: de.y })!.pos, node));
-                e.stopPropagation();
             } // otherwise, fall through to outer collection to handle drop
+            !added && e.preventDefault();
+            e.stopPropagation();
+            return added;
         }
+        return false;
     };
 
     getNodeEndpoints(context: Node, node: Node): { from: number; to: number } | null {
diff --git a/src/fields/Proxy.ts b/src/fields/Proxy.ts
index 55d1d9ea4..c076f5fe1 100644
--- a/src/fields/Proxy.ts
+++ b/src/fields/Proxy.ts
@@ -1,5 +1,5 @@
 import { Deserializable } from '../client/util/SerializationHelper';
-import { FieldWaiting, Opt } from './Doc';
+import { Field, FieldWaiting, Opt } from './Doc';
 import { primitive, serializable } from 'serializr';
 import { observable, action, runInAction, computed } from 'mobx';
 import { DocServer } from '../client/DocServer';
@@ -39,7 +39,7 @@ export class ProxyField<T extends RefField> extends ObjectField {
     }
 
     [ToScriptString]() {
-        return 'invalid';
+        return Field.toScriptString(this[ToValue](undefined)?.value); // not sure this is quite right since it doesn't recreate a proxy field, but better than 'invalid' ?
     }
     [ToString]() {
         return 'ProxyField';
diff --git a/src/fields/util.ts b/src/fields/util.ts
index e3d1abc53..e439768ee 100644
--- a/src/fields/util.ts
+++ b/src/fields/util.ts
@@ -433,7 +433,8 @@ export function updateFunction(target: any, prop: any, value: any, receiver: any
                                   lastValue = ObjectField.MakeCopy(receiver[prop]);
                               },
                               prop: 'assign list',
-                          }
+                          },
+                    diff?.items
                 );
         }
         target[Update](op);
-- 
cgit v1.2.3-70-g09d2


From 5a9af979cc293d0e3843270ee053c24bf0eb6ef5 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 5 Jul 2023 16:15:27 -0400
Subject: changed acl inheritance for docking views.

---
 src/client/documents/Documents.ts                  | 10 ++--
 src/client/util/LinkFollower.ts                    |  2 +-
 src/client/util/SharingManager.tsx                 | 70 ++++++++++------------
 src/client/views/DocComponent.tsx                  | 30 +++++-----
 src/client/views/DocumentDecorations.tsx           | 40 ++++++++-----
 .../views/collections/CollectionDockingView.tsx    | 12 ++--
 .../views/collections/CollectionTreeView.tsx       |  2 +-
 src/client/views/collections/TabDocView.tsx        |  2 +-
 src/client/views/collections/TreeView.tsx          |  8 +--
 .../collections/collectionFreeForm/MarqueeView.tsx |  2 +-
 src/client/views/nodes/ComparisonBox.tsx           |  2 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx |  2 +-
 .../formattedText/ProsemirrorExampleTransfer.ts    | 10 ++--
 src/fields/Doc.ts                                  | 11 +++-
 src/fields/util.ts                                 | 33 +++++-----
 15 files changed, 123 insertions(+), 113 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 06ff95df0..18e8b5940 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -859,7 +859,7 @@ export namespace Docs {
 
             // users placeholderDoc as proto if it exists
             const dataDoc = Doc.assign(placeholderDoc ? Doc.GetProto(placeholderDoc) : Doc.MakeDelegate(proto, protoId), dataProps, undefined, true);
-            
+
             if (placeholderDoc) {
                 dataDoc.proto = proto;
             }
@@ -1053,7 +1053,7 @@ export namespace Docs {
 
         export function FreeformDocument(documents: Array<Doc>, options: DocumentOptions, id?: string) {
             const inst = InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _xPadding: 20, _yPadding: 20, ...options, _type_collection: CollectionViewType.Freeform }, id);
-            documents.forEach(d => (d.embedContainer = inst));
+            documents.forEach(d => Doc.SetContainer(d, inst));
             return inst;
         }
 
@@ -1158,7 +1158,9 @@ export namespace Docs {
         }
 
         export function DockDocument(documents: Array<Doc>, config: string, options: DocumentOptions, id?: string) {
-            return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { treeViewFreezeChildren: 'remove|add', ...options, type_collection: CollectionViewType.Docking, dockingConfig: config }, id);
+            const ret = InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { treeViewFreezeChildren: 'remove|add', ...options, type_collection: CollectionViewType.Docking, dockingConfig: config }, id);
+            documents.map(c => Doc.SetContainer(c, ret));
+            return ret;
         }
 
         export function DirectoryImportDocument(options: DocumentOptions = {}) {
@@ -1186,7 +1188,7 @@ export namespace Docs {
                 options,
                 id
             );
-            configs.map(c => (c.doc.embedContainer = doc));
+            configs.map(c => Doc.SetContainer(c.doc, doc));
             return doc;
         }
 
diff --git a/src/client/util/LinkFollower.ts b/src/client/util/LinkFollower.ts
index f74409e42..3e526c4c0 100644
--- a/src/client/util/LinkFollower.ts
+++ b/src/client/util/LinkFollower.ts
@@ -103,7 +103,7 @@ export class LinkFollower {
                         Doc.AddDocToList(sourceDocParent, Doc.LayoutFieldKey(sourceDocParent), target);
                         movedTarget = true;
                     }
-                    target.embedContainer = sourceDocParent;
+                    Doc.SetContainer(target, sourceDocParent);
                     const moveTo = [NumCast(sourceDoc.x) + NumCast(sourceDoc.followLinkXoffset), NumCast(sourceDoc.y) + NumCast(sourceDoc.followLinkYoffset)];
                     if (sourceDoc.followLinkXoffset !== undefined && moveTo[0] !== target.x) {
                         target.x = moveTo[0];
diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx
index 534a9cfde..64b2bb5b8 100644
--- a/src/client/util/SharingManager.tsx
+++ b/src/client/util/SharingManager.tsx
@@ -1,12 +1,11 @@
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { IconButton, Size } from 'browndash-components';
 import { concat, intersection } from 'lodash';
 import { action, computed, observable, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
 import Select from 'react-select';
 import * as RequestPromise from 'request-promise';
-import { Doc, DocCastAsync, DocListCast, DocListCastAsync, HierarchyMapping, ReverseHierarchyMap } from '../../fields/Doc';
+import { Doc, DocListCast, DocListCastAsync, HierarchyMapping, ReverseHierarchyMap } from '../../fields/Doc';
 import { AclAdmin, AclPrivate, AclUnset, DocAcl, DocData } from '../../fields/DocSymbols';
 import { Id } from '../../fields/FieldSymbols';
 import { List } from '../../fields/List';
@@ -24,7 +23,6 @@ import { GroupManager, UserOptions } from './GroupManager';
 import { GroupMemberView } from './GroupMemberView';
 import { SelectionManager } from './SelectionManager';
 import './SharingManager.scss';
-import { Docs } from '../documents/Documents';
 
 export interface User {
     email: string;
@@ -166,7 +164,7 @@ export class SharingManager extends React.Component<{}> {
         // or if the 'Override Nested' checkbox is selected
         var childDocs = DocListCast(target.data);
         childDocs.map(doc => {
-            if (this.overrideNested || doc[acl]==undefined){
+            if (this.overrideNested || doc[acl] == undefined) {
                 this.setInternalSharing(recipient, permission, doc);
             }
         });
@@ -207,7 +205,7 @@ export class SharingManager extends React.Component<{}> {
         // or if the 'Override Private' checkbox is selected
         var childDocs = DocListCast(target.data);
         childDocs.map(doc => {
-            if (this.overrideNested || doc[acl]==undefined){
+            if (this.overrideNested || doc[acl] == undefined) {
                 this.setInternalGroupSharing(group, permission, doc);
             }
         });
@@ -288,7 +286,7 @@ export class SharingManager extends React.Component<{}> {
                     this.shareFromPropertiesSidebar(shareWith, permission, DocListCast(doc.data), layout);
                 }
                 if (GetEffectiveAcl(doc) === AclAdmin) {
-                    if ( shareWith == 'Public' && layout) shareWith = 'Public-layout';
+                    if (shareWith == 'Public' && layout) shareWith = 'Public-layout';
                     distributeAcls(`acl-${shareWith}`, permission, doc, undefined, undefined, isDashboard);
                 }
                 this.setDashboardBackground(doc, permission as SharingPermissions);
@@ -538,13 +536,12 @@ export class SharingManager extends React.Component<{}> {
                 const uniform = docs.map(doc => (this.layoutDocAcls ? doc : doc[DocData])).every(doc => doc?.[DocAcl]?.[userKey] === docs[0]?.[DocAcl]?.[userKey]);
                 // const permissions = uniform ? StrCast(targetDoc?.[userKey]) : '-multiple-';
                 let permissions = this.layoutDocAcls ? (targetDoc[DocAcl][userKey] ? HierarchyMapping.get(targetDoc[DocAcl][userKey])?.name : StrCast(Doc.GetProto(targetDoc)[userKey])) : StrCast(targetDoc[userKey]);
-                if (this.layoutDocAcls){
+                if (this.layoutDocAcls) {
                     if (targetDoc[DocAcl][userKey]) permissions = HierarchyMapping.get(targetDoc[DocAcl][userKey])?.name;
-                    else if (targetDoc['embedContainer'])  permissions = StrCast(Doc.GetProto(DocCast(targetDoc['embedContainer']))[userKey]);
+                    else if (targetDoc['embedContainer']) permissions = StrCast(Doc.GetProto(DocCast(targetDoc['embedContainer']))[userKey]);
                     else permissions = uniform ? StrCast(Doc.GetProto(targetDoc)?.[userKey]) : '-multiple-';
-                }
-                else permissions = uniform ? StrCast(targetDoc?.[userKey]) : '-multiple-';
-                
+                } else permissions = uniform ? StrCast(targetDoc?.[userKey]) : '-multiple-';
+
                 return !permissions ? null : (
                     <div key={userKey} className={'container'}>
                         <span className={'padding'}>{user.email}</span>
@@ -570,12 +567,11 @@ export class SharingManager extends React.Component<{}> {
         // the owner of the doc and the current user are placed at the top of the user list.
         const userKey = `acl-${normalizeEmail(Doc.CurrentUserEmail)}`;
         var curUserPermission;
-            if (this.layoutDocAcls){
-                if (targetDoc[DocAcl][userKey]) curUserPermission = HierarchyMapping.get(targetDoc[DocAcl][userKey])?.name;
-                else if (targetDoc['embedContainer']) curUserPermission = StrCast(Doc.GetProto(DocCast(targetDoc['embedContainer']))[userKey]);
-                else curUserPermission = StrCast(Doc.GetProto(targetDoc)?.[userKey]);
-            }
-            else curUserPermission = StrCast(targetDoc[userKey]);
+        if (this.layoutDocAcls) {
+            if (targetDoc[DocAcl][userKey]) curUserPermission = HierarchyMapping.get(targetDoc[DocAcl][userKey])?.name;
+            else if (targetDoc['embedContainer']) curUserPermission = StrCast(Doc.GetProto(DocCast(targetDoc['embedContainer']))[userKey]);
+            else curUserPermission = StrCast(Doc.GetProto(targetDoc)?.[userKey]);
+        } else curUserPermission = StrCast(targetDoc[userKey]);
         // const curUserPermission = HierarchyMapping.get(effectiveAcls[0])!.name
         userListContents.unshift(
             sameAuthor ? (
@@ -609,16 +605,15 @@ export class SharingManager extends React.Component<{}> {
                 .every(doc => (this.layoutDocAcls ? doc?.[DocAcl]?.[groupKey] === docs[0]?.[DocAcl]?.[groupKey] : doc?.[DocData]?.[DocAcl]?.[groupKey] === docs[0]?.[DocData]?.[DocAcl]?.[groupKey]));
             // const permissions = uniform ? StrCast(targetDoc?.[`acl-${StrCast(group.title)}`]) : '-multiple-';
             let permissions = this.layoutDocAcls ? (targetDoc[DocAcl][groupKey] ? HierarchyMapping.get(targetDoc[DocAcl][groupKey])?.name : StrCast(Doc.GetProto(targetDoc)[groupKey])) : StrCast(targetDoc[groupKey]);
-                if (this.layoutDocAcls){
-                    if (groupKey == 'acl-Public') groupKey = 'acl-Public-layout';
-                    if (targetDoc[DocAcl][groupKey]) permissions = HierarchyMapping.get(targetDoc[DocAcl][groupKey])?.name;
-                    else{
-                        if (groupKey == 'acl-Public-layout') groupKey = 'acl-Public';
-                        if (targetDoc['embedContainer']) permissions = StrCast(Doc.GetProto(DocCast(targetDoc['embedContainer']))[groupKey]);
-                        else permissions = uniform ? StrCast(Doc.GetProto(targetDoc)?.[groupKey]) : '-multiple-';
-                    }
+            if (this.layoutDocAcls) {
+                if (groupKey == 'acl-Public') groupKey = 'acl-Public-layout';
+                if (targetDoc[DocAcl][groupKey]) permissions = HierarchyMapping.get(targetDoc[DocAcl][groupKey])?.name;
+                else {
+                    if (groupKey == 'acl-Public-layout') groupKey = 'acl-Public';
+                    if (targetDoc['embedContainer']) permissions = StrCast(Doc.GetProto(DocCast(targetDoc['embedContainer']))[groupKey]);
+                    else permissions = uniform ? StrCast(Doc.GetProto(targetDoc)?.[groupKey]) : '-multiple-';
                 }
-                else permissions = uniform ? StrCast(targetDoc?.[groupKey]) : '-multiple-';
+            } else permissions = uniform ? StrCast(targetDoc?.[groupKey]) : '-multiple-';
 
             return !permissions ? null : (
                 <div key={groupKey} className={'container'}>
@@ -629,7 +624,7 @@ export class SharingManager extends React.Component<{}> {
                             <FontAwesomeIcon icon={'info-circle'} color={'#e8e8e8'} size={'sm'} style={{ backgroundColor: '#1e89d7', borderRadius: '100%', border: '1px solid #1e89d7' }} />
                         </div>
                     ) : null}
-                    <div className={"edit-actions"}>
+                    <div className={'edit-actions'}>
                         {admin || this.myDocAcls ? (
                             <select className={`permissions-dropdown-${permissions}`} value={permissions} onChange={e => this.setInternalGroupSharing(group, e.currentTarget.value)}>
                                 {this.sharingOptions(uniform, group.title === 'Override')}
@@ -649,16 +644,15 @@ export class SharingManager extends React.Component<{}> {
                 {GroupManager.Instance?.currentGroup ? <GroupMemberView group={GroupManager.Instance.currentGroup} onCloseButtonClick={action(() => (GroupManager.Instance.currentGroup = undefined))} /> : null}
                 <div className="sharing-contents">
                     <p className="share-title">
-                        <div className="share-info" onClick={() => window.open('https://brown-dash.github.io/Dash-Documentation/properties/sharing-and-permissions/', '_blank')} >
-                            <FontAwesomeIcon icon={'question-circle'} size={'sm'} onClick={() => window.open('https://brown-dash.github.io/Dash-Documentation/properties/sharing-and-permissions/', '_blank')}/>
+                        <div className="share-info" onClick={() => window.open('https://brown-dash.github.io/Dash-Documentation/properties/sharing-and-permissions/', '_blank')}>
+                            <FontAwesomeIcon icon={'question-circle'} size={'sm'} onClick={() => window.open('https://brown-dash.github.io/Dash-Documentation/properties/sharing-and-permissions/', '_blank')} />
                         </div>
                         <b>Share </b>
                         {this.focusOn(docs.length < 2 ? StrCast(targetDoc?.title, 'this document') : '-multiple-')}
                     </p>
                     <button className="share-copy-link" onClick={this.copyURL}>
-                        <FontAwesomeIcon title={"Copy Public URL"} icon={'copy'} size={'sm'} onClick={this.copyURL}/>
-                        &nbsp;
-                        Copy Public URL
+                        <FontAwesomeIcon title={'Copy Public URL'} icon={'copy'} size={'sm'} onClick={this.copyURL} />
+                        &nbsp; Copy Public URL
                     </button>
                     <div className={'close-button'} onClick={this.close}>
                         <FontAwesomeIcon icon={'times'} color={'black'} size={'lg'} />
@@ -682,7 +676,7 @@ export class SharingManager extends React.Component<{}> {
                                         }),
                                     }}
                                 />
-                                <div className='permissions-select'>
+                                <div className="permissions-select">
                                     <select className={`permissions-dropdown-${this.permissions}`} onChange={this.handlePermissionsChange} value={this.permissions}>
                                         {this.sharingOptions(true)}
                                     </select>
@@ -706,9 +700,9 @@ export class SharingManager extends React.Component<{}> {
                             </div>
                         </div>
                     ) : (
-                        <div className='share-container'>
-                            <div className='acl-container'>
-                                <div className='layoutDoc-acls'>
+                        <div className="share-container">
+                            <div className="acl-container">
+                                <div className="layoutDoc-acls">
                                     <input type="checkbox" onChange={action(() => (this.layoutDocAcls = !this.layoutDocAcls))} checked={this.layoutDocAcls} /> <label>Layout</label>
                                 </div>
                             </div>
@@ -717,7 +711,7 @@ export class SharingManager extends React.Component<{}> {
                     <div className="main-container">
                         <div className={'individual-container'}>
                             <div className="user-sort" onClick={action(() => (this.individualSort = this.individualSort === 'ascending' ? 'descending' : this.individualSort === 'descending' ? 'none' : 'ascending'))}>
-                                <div className='title-individual'>
+                                <div className="title-individual">
                                     Individuals &nbsp;
                                     {this.individualSort === 'ascending' ? (
                                         <FontAwesomeIcon icon={'caret-up'} size={'xs'} />
@@ -732,7 +726,7 @@ export class SharingManager extends React.Component<{}> {
                         </div>
                         <div className={'group-container'}>
                             <div className="user-sort" onClick={action(() => (this.groupSort = this.groupSort === 'ascending' ? 'descending' : this.groupSort === 'descending' ? 'none' : 'ascending'))}>
-                                <div className='title-group'>
+                                <div className="title-group">
                                     Groups &nbsp;
                                     <div className="group-info" onClick={action(() => GroupManager.Instance?.open())}>
                                         <FontAwesomeIcon icon={'info-circle'} color={'#e8e8e8'} size={'sm'} style={{ backgroundColor: '#1e89d7', borderRadius: '100%', border: '1px solid #1e89d7' }} />
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index f3aa8451a..1d0feec74 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -196,52 +196,52 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps>()
 
                 aclKeys.forEach(key =>
                     added.forEach(d => {
-                        if (key != 'acl-Me'){
-                            const permissionString = StrCast(Doc.GetProto(this.props.Document)[key])
-                            const permissionSymbol = ReverseHierarchyMap.get(permissionString)!.acl
-                            const permission = HierarchyMapping.get(permissionSymbol)!.name
-                            distributeAcls(key, permission, Doc.GetProto(d))
+                        if (key != 'acl-Me') {
+                            const permissionString = StrCast(Doc.GetProto(this.props.Document)[key]);
+                            const permissionSymbol = ReverseHierarchyMap.get(permissionString)!.acl;
+                            const permission = HierarchyMapping.get(permissionSymbol)!.name;
+                            distributeAcls(key, permission, Doc.GetProto(d));
                         }
                     })
                 );
 
                 if (effectiveAcl === AclAugment) {
                     added.map(doc => {
-                        doc.embedContainer = this.props.Document;
+                        Doc.SetContainer(doc, this.props.Document);
                         if (annotationKey ?? this._annotationKeySuffix()) Doc.GetProto(doc).annotationOn = this.props.Document;
                         Doc.AddDocToList(targetDataDoc, annotationKey ?? this.annotationKey, doc);
                         const parent = DocCast(doc.embedContainer);
                         doc.embedContainer && inheritParentAcls(parent, doc);
                         for (const key of Object.keys(parent)) {
-                            const symbol = ReverseHierarchyMap.get(StrCast(parent[key]))
-                            if (symbol && key.startsWith('acl')){
+                            const symbol = ReverseHierarchyMap.get(StrCast(parent[key]));
+                            if (symbol && key.startsWith('acl')) {
                                 const sharePermission = HierarchyMapping.get(symbol.acl!)!.name;
                                 const user = SharingManager.Instance?.users.filter(({ user: { email } }) => normalizeEmail(email) == key.slice(4))[0];
                                 if (user && sharePermission !== SharingPermissions.None) return Doc.AddDocToList(user.sharingDoc, 'data', doc);
                             }
                         }
                     });
-                    } else {
-                        added
+                } else {
+                    added
                         .filter(doc => [AclAdmin, AclEdit].includes(GetEffectiveAcl(doc)))
                         .map(doc => {
                             // only make a pushpin if we have acl's to edit the document
                             //DocUtils.LeavePushpin(doc);
                             doc._dragOnlyWithinContainer = undefined;
-                            doc.embedContainer = this.props.Document;
+                            Doc.SetContainer(doc, this.props.Document);
                             if (annotationKey ?? this._annotationKeySuffix()) Doc.GetProto(doc).annotationOn = this.rootDoc;
                             const parent = DocCast(doc.embedContainer);
                             doc.embedContainer && inheritParentAcls(parent, doc);
                             for (const key of Object.keys(Doc.GetProto(parent))) {
-                                const symbol = ReverseHierarchyMap.get(StrCast(parent[key]))
-                                if (symbol && key.startsWith('acl')){
+                                const symbol = ReverseHierarchyMap.get(StrCast(parent[key]));
+                                if (symbol && key.startsWith('acl')) {
                                     const sharePermission = HierarchyMapping.get(symbol.acl!)!.name;
                                     const user = SharingManager.Instance?.users.filter(({ user: { email } }) => normalizeEmail(email) == key.slice(4))[0];
                                     if (user && sharePermission !== SharingPermissions.None) return Doc.AddDocToList(user.sharingDoc, 'data', doc);
                                 }
                             }
-                    });
-                    
+                        });
+
                     const annoDocs = targetDataDoc[annotationKey ?? this.annotationKey] as List<Doc>;
                     if (annoDocs instanceof List) annoDocs.push(...added.filter(add => !annoDocs.includes(add)));
                     else targetDataDoc[annotationKey ?? this.annotationKey] = new List<Doc>(added);
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 4454a3ec1..cdd9e62d8 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -201,9 +201,9 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
     onBackgroundMove = (dragTitle: boolean, e: PointerEvent): boolean => {
         const first = SelectionManager.Views()[0];
         const effectiveLayoutAcl = GetEffectiveLayoutAcl(first.rootDoc);
-        if (effectiveLayoutAcl != AclAdmin && effectiveLayoutAcl != AclEdit && effectiveLayoutAcl != AclAugment){
+        if (effectiveLayoutAcl != AclAdmin && effectiveLayoutAcl != AclEdit && effectiveLayoutAcl != AclAugment) {
             return false;
-        }      
+        }
         const dragDocView = SelectionManager.Views()[0];
         const containers = new Set<Doc | undefined>();
         SelectionManager.Views().forEach(v => containers.add(DocCast(v.rootDoc.embedContainer)));
@@ -766,13 +766,14 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
 
         // sharing
         const acl = this.showLayoutAcl ? GetEffectiveLayoutAcl(seldocview.rootDoc) : GetEffectiveAcl(seldocview.rootDoc);
-        const docShareMode = HierarchyMapping.get(acl)!.name
+        const docShareMode = HierarchyMapping.get(acl)!.name;
         const shareMode = StrCast(docShareMode);
         var shareSymbolIcon = ReverseHierarchyMap.get(shareMode)?.image;
 
         // hide the decorations if the parent chooses to hide it or if the document itself hides it
         const hideDecorations = seldocview.props.hideDecorations || seldocview.rootDoc.hideDecorations;
-        const hideResizers = ![AclAdmin, AclEdit, AclAugment].includes(GetEffectiveLayoutAcl(seldocview.rootDoc)) || hideDecorations || seldocview.props.hideResizeHandles || seldocview.rootDoc.layout_hideResizeHandles || this._isRounding || this._isRotating;
+        const hideResizers =
+            ![AclAdmin, AclEdit, AclAugment].includes(GetEffectiveLayoutAcl(seldocview.rootDoc)) || hideDecorations || seldocview.props.hideResizeHandles || seldocview.rootDoc.layout_hideResizeHandles || this._isRounding || this._isRotating;
         const hideTitle = hideDecorations || seldocview.props.hideDecorationTitle || seldocview.rootDoc.layout_hideDecorationTitle || this._isRounding || this._isRotating;
         const hideDocumentButtonBar = hideDecorations || seldocview.props.hideDocumentButtonBar || seldocview.rootDoc.layout_hideDocumentButtonBar || this._isRounding || this._isRotating;
         // if multiple documents have been opened at the same time, then don't show open button
@@ -826,26 +827,26 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
         const radiusHandleLocation = Math.min(radiusHandle, maxDist);
 
         const sharingMenu = docShareMode ? (
-            <div className='documentDecorations-share' >
+            <div className="documentDecorations-share">
                 <div className={`documentDecorations-share${shareMode}`}>
                     &nbsp;
                     {shareSymbolIcon + ' ' + shareMode}
                     &nbsp;
-                    {!Doc.noviceMode ? 
-                        <div className='checkbox'>
-                            <div className='checkbox-box'>
-                                <input type="checkbox" checked={this.showLayoutAcl} onChange={action(() => (this.showLayoutAcl = !this.showLayoutAcl))} /> 
+                    {!Doc.noviceMode ? (
+                        <div className="checkbox">
+                            <div className="checkbox-box">
+                                <input type="checkbox" checked={this.showLayoutAcl} onChange={action(() => (this.showLayoutAcl = !this.showLayoutAcl))} />
                             </div>
-                            <div className='checkbox-text'> Layout </div>
+                            <div className="checkbox-text"> Layout </div>
                         </div>
-                    : null }
+                    ) : null}
                     &nbsp;
                 </div>
             </div>
         ) : (
             <div />
         );
-        
+
         const titleArea = this._editingTitle ? (
             <input
                 ref={this._keyinput}
@@ -860,8 +861,17 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
                 onPointerDown={e => e.stopPropagation()}
             />
         ) : (
-            <div className="documentDecorations-title" key="title" onPointerDown={e => {e.stopPropagation}}>
-                { hideTitle ? null : <span className={`documentDecorations-titleSpan${colorScheme}`} onPointerDown={this.onTitleDown}>{this.selectionTitle}</span>}
+            <div
+                className="documentDecorations-title"
+                key="title"
+                onPointerDown={e => {
+                    e.stopPropagation;
+                }}>
+                {hideTitle ? null : (
+                    <span className={`documentDecorations-titleSpan${colorScheme}`} onPointerDown={this.onTitleDown}>
+                        {this.selectionTitle}
+                    </span>
+                )}
                 {sharingMenu}
                 {!useLock ? null : (
                     <Tooltip key="lock" title={<div className="dash-tooltip">toggle ability to interact with document</div>} placement="top">
@@ -872,7 +882,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
                 )}
             </div>
         );
-        
+
         return (
             <div className={`documentDecorations${colorScheme}`} style={{ opacity: this._showNothing ? 0.1 : undefined }}>
                 <div
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 32fb4d8df..ce9eb9f17 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -461,7 +461,7 @@ export class CollectionDockingView extends CollectionSubView() {
             const newtabdocs = origtabdocs.map(origtabdoc => Doc.MakeEmbedding(origtabdoc));
             if (newtabdocs.length) {
                 Doc.GetProto(newtab).data = new List<Doc>(newtabdocs);
-                newtabdocs.forEach(ntab => (ntab.embedContainer = newtab));
+                newtabdocs.forEach(ntab => Doc.SetContainer(ntab, newtab));
             }
             json = json.replace(origtab[Id], newtab[Id]);
             return newtab;
@@ -497,11 +497,11 @@ export class CollectionDockingView extends CollectionSubView() {
     tabCreated = (tab: any) => {
         const aclKeys = Object.keys(Doc.GetProto(this.props.Document)[DocAcl] ?? {});
         aclKeys.forEach(key => {
-            if (key != 'acl-Me'){
-                const permissionString = StrCast(Doc.GetProto(this.props.Document)[key])
-                const permissionSymbol = ReverseHierarchyMap.get(permissionString)!.acl
-                const permission = HierarchyMapping.get(permissionSymbol)!.name
-                distributeAcls(key, permission, Doc.GetProto(tab))
+            if (key != 'acl-Me') {
+                const permissionString = StrCast(Doc.GetProto(this.props.Document)[key]);
+                const permissionSymbol = ReverseHierarchyMap.get(permissionString)!.acl;
+                const permission = HierarchyMapping.get(permissionSymbol)!.name;
+                distributeAcls(key, permission, Doc.GetProto(tab));
             }
         });
         this.tabMap.add(tab);
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 4cd3885f5..d78a0e781 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -180,7 +180,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
         const doAddDoc = (doc: Doc | Doc[]) =>
             (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => {
                 const res = flg && Doc.AddDocToList(this.doc[DocData], this.props.fieldKey, doc, relativeTo, before);
-                res && (doc.embedContainer = this.props.Document);
+                res && Doc.SetContainer(doc, this.props.Document);
                 return res;
             }, true);
         if (this.doc.resolvedDataDoc instanceof Promise) return false;
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 4d780f46b..3473eee18 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -262,7 +262,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
             pinDoc.presMovement = doc.type === DocumentType.SCRIPTING || pinProps?.pinDocLayout ? PresMovement.None : PresMovement.Zoom;
             pinDoc.presDuration = pinDoc.presDuration ?? 1000;
             pinDoc.groupWithUp = false;
-            pinDoc.embedContainer = curPres;
+            Doc.SetContainer(pinDoc, curPres);
             // these should potentially all be props passed down by the CollectionTreeView to the TreeView elements.  That way the PresBox could configure all of its children at render time
             pinDoc.treeViewRenderAsBulletHeader = true; // forces a tree view to render the document next to the bullet in the header area
             pinDoc.treeViewHeaderWidth = '100%'; // forces the header to grow to be the same size as its largest sibling.
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 8d8d895c6..a2269075d 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -392,7 +392,7 @@ export class TreeView extends React.Component<TreeViewProps> {
             const innerAdd = (doc: Doc) => {
                 const dataIsComputed = ComputedField.WithoutComputed(() => FieldValue(this.dataDoc[this.fieldKey])) instanceof ComputedField;
                 const added = (!dataIsComputed || (this.dropping && this.moving)) && Doc.AddDocToList(this.dataDoc, this.fieldKey, doc);
-                dataIsComputed && (doc.embedContainer = this.doc.embedContainer);
+                dataIsComputed && Doc.SetContainer(doc, this.doc.embedContainer);
                 return added;
             };
             return (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && innerAdd(doc), true as boolean);
@@ -455,7 +455,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                     const innerAdd = (doc: Doc) => {
                         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 && (doc.embedContainer = this.doc.embedContainer);
+                        dataIsComputed && Doc.SetContainer(doc, this.doc.embedContainer);
                         return added;
                     };
                     return (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && innerAdd(doc), true as boolean);
@@ -563,7 +563,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.embedContainer = this.doc.embedContainer);
+                !dataIsComputed && added && Doc.SetContainer(doc, this.doc.embedContainer);
 
                 return added;
             };
@@ -1192,7 +1192,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                         TreeView._editTitleOnLoad = editTitle ? { id: child[Id], parent } : undefined;
                         Doc.AddDocToList(newParent, fieldKey, child, addAfter, false);
                         newParent.treeViewOpen = true;
-                        child.embedContainer = treeView.Document;
+                        Doc.SetContainer(child, treeView.Document);
                     }
                 };
                 const indent = i === 0 ? undefined : (editTitle: boolean) => dentDoc(editTitle, docs[i - 1], undefined, treeViewRefs.get(docs[i - 1]));
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 9b0abc48b..764b1e08a 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -392,7 +392,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
         newCollection.layout_fitWidth = true;
         newCollection['acl-Public'] = Doc.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.Augment;
         selected.forEach(d => {
-            d.embedContainer = newCollection;
+            Doc.SetContainer(d, newCollection);
             d['acl-Public'] = Doc.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.Augment;
         });
         this.hideMarquee();
diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx
index 2290e0711..ca5ec9389 100644
--- a/src/client/views/nodes/ComparisonBox.tsx
+++ b/src/client/views/nodes/ComparisonBox.tsx
@@ -46,7 +46,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
         if (dropEvent.complete.docDragData) {
             const droppedDocs = dropEvent.complete.docDragData?.droppedDocuments;
             const added = dropEvent.complete.docDragData.moveDocument?.(droppedDocs, this.rootDoc, (doc: Doc | Doc[]) => this.addDoc(doc instanceof Doc ? doc : doc.lastElement(), fieldKey));
-            droppedDocs.lastElement().embedContainer = this.dataDoc;
+            Doc.SetContainer(droppedDocs.lastElement(), this.dataDoc);
             !added && e.preventDefault();
             e.stopPropagation(); // prevent parent Doc from registering new position so that it snaps back into place
             return added;
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 202a9f851..e5ea8e0c1 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -564,7 +564,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                     }
                     if (added) {
                         draggedDoc._freeform_fitContentsToBox = true;
-                        draggedDoc.embedContainer = this.rootDoc;
+                        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));
                     }
diff --git a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts
index d2273c91c..112a0d87e 100644
--- a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts
+++ b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts
@@ -4,7 +4,7 @@ import { Schema } from 'prosemirror-model';
 import { splitListItem, wrapInList } from 'prosemirror-schema-list';
 import { EditorState, NodeSelection, TextSelection, Transaction } from 'prosemirror-state';
 import { liftTarget } from 'prosemirror-transform';
-import { AclAdmin, AclAugment, AclEdit} from '../../../../fields/DocSymbols';
+import { AclAdmin, AclAugment, AclEdit } from '../../../../fields/DocSymbols';
 import { GetEffectiveAcl } from '../../../../fields/util';
 import { Utils } from '../../../../Utils';
 import { Docs } from '../../../documents/Documents';
@@ -50,8 +50,8 @@ export function buildKeymap<S extends Schema<any>>(schema: S, props: any, mapKey
         switch (GetEffectiveAcl(props.DataDoc)) {
             case AclAugment:
                 const prevNode = state.selection.$cursor.nodeBefore;
-                const prevUser = prevNode.marks[prevNode.marks.length-1].attrs.userid
-                if (prevUser != Doc.CurrentUserEmail){
+                const prevUser = !prevNode ? Doc.CurrentUserEmail : prevNode.marks[prevNode.marks.length - 1].attrs.userid;
+                if (prevUser != Doc.CurrentUserEmail) {
                     return false;
                 }
         }
@@ -263,7 +263,7 @@ export function buildKeymap<S extends Schema<any>>(schema: S, props: any, mapKey
     bind('Backspace', (state: EditorState, dispatch: (tx: Transaction) => void) => {
         if (props.onKey?.(event, props)) return true;
         if (!canEdit(state)) return true;
-        
+
         if (
             !deleteSelection(state, (tx: Transaction) => {
                 dispatch(updateBullets(tx, schema));
@@ -334,7 +334,7 @@ export function buildKeymap<S extends Schema<any>>(schema: S, props: any, mapKey
 
     //Command to create a blank space
     bind('Space', (state: EditorState, dispatch: (tx: Transaction) => void) => {
-        if (GetEffectiveAcl(props.DataDoc)!=AclEdit && GetEffectiveAcl(props.DataDoc)!=AclAugment && GetEffectiveAcl(props.DataDoc)!=AclAdmin) return true;
+        if (GetEffectiveAcl(props.DataDoc) != AclEdit && GetEffectiveAcl(props.DataDoc) != AclAugment && GetEffectiveAcl(props.DataDoc) != AclAdmin) return true;
         const marks = state.storedMarks || (state.selection.$to.parentOffset && state.selection.$from.marks());
         dispatch(splitMetadata(marks, state.tr));
         return false;
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 99712fb04..9c138d348 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -20,7 +20,6 @@ import {
     AclEdit,
     AclPrivate,
     AclReadonly,
-    AclSelfEdit,
     AclUnset,
     Animation,
     CachedUpdates,
@@ -138,7 +137,7 @@ export const HierarchyMapping: Map<symbol, { level:aclLevel; name: SharingPermis
     [AclAdmin,    { level: aclLevel.admin,        name: SharingPermissions.Admin,   image: '⬢' }],
     [AclUnset,    { level: aclLevel.unset,        name: SharingPermissions.Unset,   image: '▲' }],
 ]);
-export const ReverseHierarchyMap: Map<string, { level: aclLevel; acl: symbol ; image: string}> = new Map(Array.from(HierarchyMapping.entries()).map(value => [value[1].name, { level: value[1].level, acl: value[0], image: value[1].image }]));
+export const ReverseHierarchyMap: Map<string, { level: aclLevel; acl: symbol; image: string }> = new Map(Array.from(HierarchyMapping.entries()).map(value => [value[1].name, { level: value[1].level, acl: value[0], image: value[1].image }]));
 
 // caches the document access permissions for the current user.
 // this recursively updates all protos as well.
@@ -478,6 +477,14 @@ export namespace Doc {
     //     });
     // }
 
+    export function SetContainer(doc: Doc, container: Doc) {
+        doc.embedContainer = container;
+        if (Doc.GetProto(container).author === doc.author) {
+            Object.keys(Doc.GetProto(container))
+                .filter(key => key.startsWith('acl'))
+                .forEach(key => (doc[key] = Doc.GetProto(container)[key]));
+        }
+    }
     export function RunCachedUpdate(doc: Doc, field: string) {
         const update = doc[CachedUpdates][field];
         if (update) {
diff --git a/src/fields/util.ts b/src/fields/util.ts
index 0f613d926..48de36efe 100644
--- a/src/fields/util.ts
+++ b/src/fields/util.ts
@@ -131,10 +131,10 @@ export function inheritParentAcls(parent: Doc, child: Doc) {
     for (const key of Object.keys(parent)) {
         // if the default acl mode is private, then don't inherit the acl-Public permission, but set it to private.
         // const permission: string = key === 'acl-Public' && Doc.defaultAclPrivate ? AclPrivate : parent[key];
-        const symbol = ReverseHierarchyMap.get(StrCast(parent[key]))
-        if (symbol){
+        const symbol = ReverseHierarchyMap.get(StrCast(parent[key]));
+        if (symbol) {
             const sharePermission = HierarchyMapping.get(symbol.acl!)!.name;
-            key.startsWith('acl') && distributeAcls(key, sharePermission, child)
+            key.startsWith('acl') && distributeAcls(key, sharePermission, child);
         }
     }
 }
@@ -171,7 +171,7 @@ const getEffectiveAclCache = computedFn(function (target: any, user?: string) {
 // return layout acl from cache or chache the acl and return.
 const getEffectiveLayoutAclCache = computedFn(function (target: any, user?: string) {
     return getEffectiveLayoutAcl(target, user);
-    }, true);
+}, true);
 
 /**
  * Calculates the effective access right to a document for the current user.
@@ -183,13 +183,13 @@ export function GetEffectiveAcl(target: any, user?: string): symbol {
 }
 
 /**
-* Calculates the effective access layout right to a document for the current user. By getting the container's effective acl if the layout acl isn't set.
-*/
+ * Calculates the effective access layout right to a document for the current user. By getting the container's effective acl if the layout acl isn't set.
+ */
 export function GetEffectiveLayoutAcl(target: any, user?: string): symbol {
     if (!target) return AclPrivate;
     if (target[UpdatingFromServer]) return AclAdmin;
     return getEffectiveLayoutAclCache(target, user);
-    }
+}
 
 function getPropAcl(target: any, prop: string | symbol | number) {
     if (typeof prop === 'symbol' || target[UpdatingFromServer]) return AclAdmin; // requesting the UpdatingFromServer prop or AclSym must always go through to keep the local DB consistent
@@ -234,9 +234,9 @@ function getEffectiveAcl(target: any, user?: string): symbol {
 }
 
 /**
-* Returns the layout acl that is effective on the document passed through as the target. If no layout acls
-* have been set, it returns the regular acls for the document target is contained in.
-*/
+ * Returns the layout acl that is effective on the document passed through as the target. If no layout acls
+ * have been set, it returns the regular acls for the document target is contained in.
+ */
 function getEffectiveLayoutAcl(target: any, user?: string): symbol {
     const targetAcls = target[DocAcl];
 
@@ -248,27 +248,24 @@ function getEffectiveLayoutAcl(target: any, user?: string): symbol {
             if ((GetCachedGroupByName(entity) || userChecked === entity || entity === 'Me') && entity != 'Public') {
                 if (effectiveAcl && HierarchyMapping.get(value as symbol)!.level > HierarchyMapping.get(effectiveAcl)!.level) {
                     effectiveAcl = value as symbol;
-                }
-                else{
+                } else {
                     effectiveAcl = value as symbol;
                 }
             }
         }
 
-        if (effectiveAcl){
+        if (effectiveAcl) {
             return DocServer?.Control?.isReadOnly?.() && HierarchyMapping.get(effectiveAcl)!.level < aclLevel.editable ? AclEdit : effectiveAcl;
-        }
-        else{
+        } else {
             return GetEffectiveAcl(Doc.GetProto(target['embedContainer']), user);
         }
     }
     // authored documents are private until an ACL is set.
     const targetAuthor = target.__fieldTuples?.author || target.author; // target may be a Doc of Proxy, so check __fieldTuples.author and .author
     if (targetAuthor && targetAuthor !== userChecked) return AclPrivate;
-        return AclAdmin;
+    return AclAdmin;
 }
 
-
 /**
  * Recursively distributes the access right for a user across the children of a document and its annotations.
  * @param key the key storing the access right (e.g. acl-groupname)
@@ -286,7 +283,7 @@ export function distributeAcls(key: string, acl: SharingPermissions, target: Doc
             //apparently we can't call updateCachedAcls twice (once for the main dashboard, and again for the nested dashboard...???)
             updateCachedAcls(target);
         }
-        return;
+        //return;
     }
     visited.push(target);
 
-- 
cgit v1.2.3-70-g09d2


From 54308259a8cd3ac98aaee550ea01ad97f17172e6 Mon Sep 17 00:00:00 2001
From: Geireann Lindfield Roberts <60007097+geireann@users.noreply.github.com>
Date: Mon, 17 Jul 2023 23:11:35 -0400
Subject: so many updates

---
 deploy/index.html                                  |   7 +-
 deploy/loader.css                                  |   5 +-
 package-lock.json                                  | 232 +++----
 package.json                                       |   2 +-
 src/client/documents/Documents.ts                  |   6 +-
 src/client/util/CurrentUserUtils.ts                |  63 +-
 src/client/util/DropConverter.ts                   |   2 +-
 src/client/util/ReportManager.tsx                  |   4 +-
 src/client/util/SettingsManager.scss               |  93 +--
 src/client/util/SettingsManager.tsx                | 186 ++++--
 src/client/views/AntimodeMenu.scss                 |  32 +-
 src/client/views/AntimodeMenu.tsx                  |   5 +
 src/client/views/DashboardView.scss                |  22 +
 src/client/views/DashboardView.tsx                 |  98 ++-
 src/client/views/EditableView.tsx                  |  75 ++-
 src/client/views/GestureOverlay.tsx                |   2 +-
 src/client/views/MainView.scss                     |  20 -
 src/client/views/MainView.tsx                      |  13 +-
 src/client/views/MainViewModal.scss                |   6 +-
 src/client/views/MainViewModal.tsx                 |   7 +-
 src/client/views/PropertiesButtons.scss            |   8 +-
 src/client/views/PropertiesButtons.tsx             |  98 ++-
 .../views/PropertiesDocBacklinksSelector.scss      |   2 +-
 .../views/PropertiesDocBacklinksSelector.tsx       |   2 +-
 src/client/views/PropertiesDocContextSelector.tsx  |   1 +
 src/client/views/PropertiesSection.scss            |  24 +
 src/client/views/PropertiesSection.tsx             |  51 ++
 src/client/views/PropertiesView.scss               | 364 +---------
 src/client/views/PropertiesView.tsx                | 743 ++++++++++-----------
 src/client/views/StyleProvider.tsx                 |  10 +-
 src/client/views/UndoStack.scss                    |   9 +-
 src/client/views/UndoStack.tsx                     |  48 +-
 src/client/views/collections/CollectionMenu.scss   | 651 +-----------------
 src/client/views/collections/CollectionMenu.tsx    |  51 +-
 .../views/collections/CollectionTreeView.tsx       |   2 +
 src/client/views/collections/TabDocView.scss       |  17 -
 src/client/views/collections/TabDocView.tsx        | 103 ++-
 src/client/views/collections/TreeView.scss         |  36 +-
 src/client/views/collections/TreeView.tsx          |  35 +-
 .../collectionFreeForm/MarqueeOptionsMenu.tsx      |  69 +-
 .../collectionLinear/CollectionLinearView.tsx      |  51 +-
 src/client/views/global/globalScripts.ts           |  49 +-
 src/client/views/linking/LinkPopup.scss            |   5 -
 src/client/views/linking/LinkPopup.tsx             |   4 +-
 src/client/views/nodes/DocumentContentsView.tsx    |   2 +-
 src/client/views/nodes/DocumentView.tsx            |   4 +-
 .../views/nodes/FontIconBox/ButtonInterface.ts     |  12 +
 .../views/nodes/FontIconBox/FontIconBadge.scss     |  11 +
 .../views/nodes/FontIconBox/FontIconBadge.tsx      |  37 +
 .../views/nodes/FontIconBox/FontIconBox.scss       | 438 ++++++++++++
 src/client/views/nodes/FontIconBox/FontIconBox.tsx | 412 ++++++++++++
 src/client/views/nodes/button/FontIconBox.scss     | 438 ------------
 src/client/views/nodes/button/FontIconBox.tsx      | 385 -----------
 src/client/views/pdf/AnchorMenu.tsx                | 121 ++--
 src/client/views/search/SearchBox.scss             |   3 +-
 src/client/views/search/SearchBox.tsx              |   7 +-
 src/client/views/selectedDoc/SelectedDocView.scss  |   3 +
 src/client/views/selectedDoc/SelectedDocView.tsx   |  47 ++
 src/client/views/selectedDoc/index.ts              |   1 +
 src/client/views/topbar/TopBar.tsx                 |  36 +-
 60 files changed, 2279 insertions(+), 2991 deletions(-)
 create mode 100644 src/client/views/PropertiesSection.scss
 create mode 100644 src/client/views/PropertiesSection.tsx
 create mode 100644 src/client/views/nodes/FontIconBox/ButtonInterface.ts
 create mode 100644 src/client/views/nodes/FontIconBox/FontIconBadge.scss
 create mode 100644 src/client/views/nodes/FontIconBox/FontIconBadge.tsx
 create mode 100644 src/client/views/nodes/FontIconBox/FontIconBox.scss
 create mode 100644 src/client/views/nodes/FontIconBox/FontIconBox.tsx
 delete mode 100644 src/client/views/nodes/button/FontIconBox.scss
 delete mode 100644 src/client/views/nodes/button/FontIconBox.tsx
 create mode 100644 src/client/views/selectedDoc/SelectedDocView.scss
 create mode 100644 src/client/views/selectedDoc/SelectedDocView.tsx
 create mode 100644 src/client/views/selectedDoc/index.ts

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

diff --git a/deploy/index.html b/deploy/index.html
index f8003f126..c8ad2a8d4 100644
--- a/deploy/index.html
+++ b/deploy/index.html
@@ -5,7 +5,7 @@
     <link rel="preconnect" href="https://fonts.googleapis.com">
     <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
     <link
-        href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:ital,wght@0,300;0,400;0,500;0,700;1,300;1,400;1,500;1,700&family=Lato:ital,wght@0,300;0,400;0,700;1,300;1,400;1,700&family=Merriweather:ital,wght@0,300;0,400;0,700;1,300;1,400;1,700&family=Roboto:ital,wght@0,300;0,400;0,500;1,300;1,400;1,500&display=swap"
+        href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:ital,wght@0,300;0,400;0,500;0,700;1,300;1,400;1,500;1,700&family=Lato:ital,wght@0,300;0,400;0,700;1,300;1,400;1,700&family=Merriweather:ital,wght@0,300;0,400;0,700;1,300;1,400;1,700&family=Roboto:ital,wght@0,300;0,400;0,500;1,300;1,400;1,500&family=Nunito:ital,wght@0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;0,1000;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900;1,1000&family=Roboto+Mono:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,100;1,200;1,300;1,400;1,500;1,600;1,700&display=swap"
         rel="stylesheet">
     <link rel="shortcut icon" type="image/jpg" href="./assets/favicon.png" />
     <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
@@ -67,8 +67,9 @@
         }
 
         .dash-animation-container {
-            width: 10vw;
-            height: 10vw;
+            width: fit-content;
+            height: fit-content;
+            padding: 20px;
             display: flex;
             align-items: center;
             justify-content: center;
diff --git a/deploy/loader.css b/deploy/loader.css
index 4be0cc98c..4d5e04d71 100644
--- a/deploy/loader.css
+++ b/deploy/loader.css
@@ -36,8 +36,9 @@
 }
 
 .dash-animation-container {
-    width: 10vw;
-    height: 10vw;
+    width: fit-content;
+    height: fit-content;
+    padding: 20px;
     display: flex;
     align-items: center;
     justify-content: center;
diff --git a/package-lock.json b/package-lock.json
index 84c1e6219..215468914 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -22,36 +22,42 @@
             }
         },
         "@babel/compat-data": {
-            "version": "7.22.6",
-            "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.6.tgz",
-            "integrity": "sha512-29tfsWTq2Ftu7MXmimyC0C5FDZv5DYxOZkh3XD3+QW4V/BYuv/LyEsjj3c0hqedEaDt6DBfDvexMKU8YevdqFg=="
+            "version": "7.22.9",
+            "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.9.tgz",
+            "integrity": "sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ=="
         },
         "@babel/core": {
-            "version": "7.22.8",
-            "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.8.tgz",
-            "integrity": "sha512-75+KxFB4CZqYRXjx4NlR4J7yGvKumBuZTmV4NV6v09dVXXkuYVYLT68N6HCzLvfJ+fWCxQsntNzKwwIXL4bHnw==",
+            "version": "7.22.9",
+            "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.9.tgz",
+            "integrity": "sha512-G2EgeufBcYw27U4hhoIwFcgc1XU7TlXJ3mv04oOv1WCuo900U/anZSPzEqNjwdjgffkk2Gs0AN0dW1CKVLcG7w==",
             "requires": {
                 "@ampproject/remapping": "^2.2.0",
                 "@babel/code-frame": "^7.22.5",
-                "@babel/generator": "^7.22.7",
-                "@babel/helper-compilation-targets": "^7.22.6",
-                "@babel/helper-module-transforms": "^7.22.5",
+                "@babel/generator": "^7.22.9",
+                "@babel/helper-compilation-targets": "^7.22.9",
+                "@babel/helper-module-transforms": "^7.22.9",
                 "@babel/helpers": "^7.22.6",
                 "@babel/parser": "^7.22.7",
                 "@babel/template": "^7.22.5",
                 "@babel/traverse": "^7.22.8",
                 "@babel/types": "^7.22.5",
-                "@nicolo-ribaudo/semver-v6": "^6.3.3",
                 "convert-source-map": "^1.7.0",
                 "debug": "^4.1.0",
                 "gensync": "^1.0.0-beta.2",
-                "json5": "^2.2.2"
+                "json5": "^2.2.2",
+                "semver": "^6.3.1"
             },
             "dependencies": {
-                "@nicolo-ribaudo/semver-v6": {
-                    "version": "6.3.3",
-                    "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/semver-v6/-/semver-v6-6.3.3.tgz",
-                    "integrity": "sha512-3Yc1fUTs69MG/uZbJlLSI3JISMn2UV2rg+1D/vROUqZyh3l6iYHCs7GMp+M40ZD7yOdDbYjJcU1oTJhrc+dGKg=="
+                "@babel/generator": {
+                    "version": "7.22.9",
+                    "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.9.tgz",
+                    "integrity": "sha512-KtLMbmicyuK2Ak/FTCJVbDnkN1SlT8/kceFTiuDiiRUUSMnHMidxSCdG4ndkTOHHpoomWe/4xkvHkEOncwjYIw==",
+                    "requires": {
+                        "@babel/types": "^7.22.5",
+                        "@jridgewell/gen-mapping": "^0.3.2",
+                        "@jridgewell/trace-mapping": "^0.3.17",
+                        "jsesc": "^2.5.1"
+                    }
                 },
                 "debug": {
                     "version": "4.3.4",
@@ -70,6 +76,11 @@
                     "version": "2.1.2",
                     "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
                     "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+                },
+                "semver": {
+                    "version": "6.3.1",
+                    "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+                    "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
                 }
             }
         },
@@ -101,22 +112,17 @@
             }
         },
         "@babel/helper-compilation-targets": {
-            "version": "7.22.6",
-            "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.6.tgz",
-            "integrity": "sha512-534sYEqWD9VfUm3IPn2SLcH4Q3P86XL+QvqdC7ZsFrzyyPF3T4XGiVghF6PTYNdWg6pXuoqXxNQAhbYeEInTzA==",
+            "version": "7.22.9",
+            "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.9.tgz",
+            "integrity": "sha512-7qYrNM6HjpnPHJbopxmb8hSPoZ0gsX8IvUS32JGVoy+pU9e5N0nLr1VjJoR6kA4d9dmGLxNYOjeB8sUDal2WMw==",
             "requires": {
-                "@babel/compat-data": "^7.22.6",
+                "@babel/compat-data": "^7.22.9",
                 "@babel/helper-validator-option": "^7.22.5",
-                "@nicolo-ribaudo/semver-v6": "^6.3.3",
                 "browserslist": "^4.21.9",
-                "lru-cache": "^5.1.1"
+                "lru-cache": "^5.1.1",
+                "semver": "^6.3.1"
             },
             "dependencies": {
-                "@nicolo-ribaudo/semver-v6": {
-                    "version": "6.3.3",
-                    "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/semver-v6/-/semver-v6-6.3.3.tgz",
-                    "integrity": "sha512-3Yc1fUTs69MG/uZbJlLSI3JISMn2UV2rg+1D/vROUqZyh3l6iYHCs7GMp+M40ZD7yOdDbYjJcU1oTJhrc+dGKg=="
-                },
                 "lru-cache": {
                     "version": "5.1.1",
                     "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
@@ -125,6 +131,11 @@
                         "yallist": "^3.0.2"
                     }
                 },
+                "semver": {
+                    "version": "6.3.1",
+                    "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+                    "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
+                },
                 "yallist": {
                     "version": "3.1.1",
                     "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
@@ -133,19 +144,19 @@
             }
         },
         "@babel/helper-create-class-features-plugin": {
-            "version": "7.22.6",
-            "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.6.tgz",
-            "integrity": "sha512-iwdzgtSiBxF6ni6mzVnZCF3xt5qE6cEA0J7nFt8QOAWZ0zjCFceEgpn3vtb2V7WFR6QzP2jmIFOHMTRo7eNJjQ==",
+            "version": "7.22.9",
+            "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.9.tgz",
+            "integrity": "sha512-Pwyi89uO4YrGKxL/eNJ8lfEH55DnRloGPOseaA8NFNL6jAUnn+KccaISiFazCj5IolPPDjGSdzQzXVzODVRqUQ==",
             "requires": {
                 "@babel/helper-annotate-as-pure": "^7.22.5",
                 "@babel/helper-environment-visitor": "^7.22.5",
                 "@babel/helper-function-name": "^7.22.5",
                 "@babel/helper-member-expression-to-functions": "^7.22.5",
                 "@babel/helper-optimise-call-expression": "^7.22.5",
-                "@babel/helper-replace-supers": "^7.22.5",
+                "@babel/helper-replace-supers": "^7.22.9",
                 "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5",
                 "@babel/helper-split-export-declaration": "^7.22.6",
-                "@nicolo-ribaudo/semver-v6": "^6.3.3"
+                "semver": "^6.3.1"
             },
             "dependencies": {
                 "@babel/helper-annotate-as-pure": {
@@ -156,21 +167,21 @@
                         "@babel/types": "^7.22.5"
                     }
                 },
-                "@nicolo-ribaudo/semver-v6": {
-                    "version": "6.3.3",
-                    "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/semver-v6/-/semver-v6-6.3.3.tgz",
-                    "integrity": "sha512-3Yc1fUTs69MG/uZbJlLSI3JISMn2UV2rg+1D/vROUqZyh3l6iYHCs7GMp+M40ZD7yOdDbYjJcU1oTJhrc+dGKg=="
+                "semver": {
+                    "version": "6.3.1",
+                    "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+                    "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
                 }
             }
         },
         "@babel/helper-create-regexp-features-plugin": {
-            "version": "7.22.6",
-            "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.6.tgz",
-            "integrity": "sha512-nBookhLKxAWo/TUCmhnaEJyLz2dekjQvv5SRpE9epWQBcpedWLKt8aZdsuT9XV5ovzR3fENLjRXVT0GsSlGGhA==",
+            "version": "7.22.9",
+            "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.9.tgz",
+            "integrity": "sha512-+svjVa/tFwsNSG4NEy1h85+HQ5imbT92Q5/bgtS7P0GTQlP8WuFdqsiABmQouhiFGyV66oGxZFpeYHza1rNsKw==",
             "requires": {
                 "@babel/helper-annotate-as-pure": "^7.22.5",
-                "@nicolo-ribaudo/semver-v6": "^6.3.3",
-                "regexpu-core": "^5.3.1"
+                "regexpu-core": "^5.3.1",
+                "semver": "^6.3.1"
             },
             "dependencies": {
                 "@babel/helper-annotate-as-pure": {
@@ -181,10 +192,10 @@
                         "@babel/types": "^7.22.5"
                     }
                 },
-                "@nicolo-ribaudo/semver-v6": {
-                    "version": "6.3.3",
-                    "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/semver-v6/-/semver-v6-6.3.3.tgz",
-                    "integrity": "sha512-3Yc1fUTs69MG/uZbJlLSI3JISMn2UV2rg+1D/vROUqZyh3l6iYHCs7GMp+M40ZD7yOdDbYjJcU1oTJhrc+dGKg=="
+                "semver": {
+                    "version": "6.3.1",
+                    "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+                    "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
                 }
             }
         },
@@ -264,18 +275,15 @@
             }
         },
         "@babel/helper-module-transforms": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.5.tgz",
-            "integrity": "sha512-+hGKDt/Ze8GFExiVHno/2dvG5IdstpzCq0y4Qc9OJ25D4q3pKfiIP/4Vp3/JvhDkLKsDK2api3q3fpIgiIF5bw==",
+            "version": "7.22.9",
+            "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.9.tgz",
+            "integrity": "sha512-t+WA2Xn5K+rTeGtC8jCsdAH52bjggG5TKRuRrAGNM/mjIbO4GxvlLMFOEz9wXY5I2XQ60PMFsAG2WIcG82dQMQ==",
             "requires": {
                 "@babel/helper-environment-visitor": "^7.22.5",
                 "@babel/helper-module-imports": "^7.22.5",
                 "@babel/helper-simple-access": "^7.22.5",
-                "@babel/helper-split-export-declaration": "^7.22.5",
-                "@babel/helper-validator-identifier": "^7.22.5",
-                "@babel/template": "^7.22.5",
-                "@babel/traverse": "^7.22.5",
-                "@babel/types": "^7.22.5"
+                "@babel/helper-split-export-declaration": "^7.22.6",
+                "@babel/helper-validator-identifier": "^7.22.5"
             }
         },
         "@babel/helper-optimise-call-expression": {
@@ -292,14 +300,13 @@
             "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ=="
         },
         "@babel/helper-remap-async-to-generator": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.5.tgz",
-            "integrity": "sha512-cU0Sq1Rf4Z55fgz7haOakIyM7+x/uCFwXpLPaeRzfoUtAEAuUZjZvFPjL/rk5rW693dIgn2hng1W7xbT7lWT4g==",
+            "version": "7.22.9",
+            "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.9.tgz",
+            "integrity": "sha512-8WWC4oR4Px+tr+Fp0X3RHDVfINGpF3ad1HIbrc8A77epiR6eMMc6jsgozkzT2uDiOOdoS9cLIQ+XD2XvI2WSmQ==",
             "requires": {
                 "@babel/helper-annotate-as-pure": "^7.22.5",
                 "@babel/helper-environment-visitor": "^7.22.5",
-                "@babel/helper-wrap-function": "^7.22.5",
-                "@babel/types": "^7.22.5"
+                "@babel/helper-wrap-function": "^7.22.9"
             },
             "dependencies": {
                 "@babel/helper-annotate-as-pure": {
@@ -313,16 +320,13 @@
             }
         },
         "@babel/helper-replace-supers": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.5.tgz",
-            "integrity": "sha512-aLdNM5I3kdI/V9xGNyKSF3X/gTyMUBohTZ+/3QdQKAA9vxIiy12E+8E2HoOP1/DjeqU+g6as35QHJNMDDYpuCg==",
+            "version": "7.22.9",
+            "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.9.tgz",
+            "integrity": "sha512-LJIKvvpgPOPUThdYqcX6IXRuIcTkcAub0IaDRGCZH0p5GPUp7PhRU9QVgFcDDd51BaPkk77ZjqFwh6DZTAEmGg==",
             "requires": {
                 "@babel/helper-environment-visitor": "^7.22.5",
                 "@babel/helper-member-expression-to-functions": "^7.22.5",
-                "@babel/helper-optimise-call-expression": "^7.22.5",
-                "@babel/template": "^7.22.5",
-                "@babel/traverse": "^7.22.5",
-                "@babel/types": "^7.22.5"
+                "@babel/helper-optimise-call-expression": "^7.22.5"
             }
         },
         "@babel/helper-simple-access": {
@@ -365,13 +369,12 @@
             "integrity": "sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw=="
         },
         "@babel/helper-wrap-function": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.5.tgz",
-            "integrity": "sha512-bYqLIBSEshYcYQyfks8ewYA8S30yaGSeRslcvKMvoUk6HHPySbxHq9YRi6ghhzEU+yhQv9bP/jXnygkStOcqZw==",
+            "version": "7.22.9",
+            "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.9.tgz",
+            "integrity": "sha512-sZ+QzfauuUEfxSEjKFmi3qDSHgLsTPK/pEpoD/qonZKOtTPTLbf59oabPQ4rKekt9lFcj/hTZaOhWwFYrgjk+Q==",
             "requires": {
                 "@babel/helper-function-name": "^7.22.5",
                 "@babel/template": "^7.22.5",
-                "@babel/traverse": "^7.22.5",
                 "@babel/types": "^7.22.5"
             }
         },
@@ -1472,12 +1475,12 @@
             }
         },
         "@babel/plugin-transform-typescript": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.22.5.tgz",
-            "integrity": "sha512-SMubA9S7Cb5sGSFFUlqxyClTA9zWJ8qGQrppNUm05LtFuN1ELRFNndkix4zUJrC9F+YivWwa1dHMSyo0e0N9dA==",
+            "version": "7.22.9",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.22.9.tgz",
+            "integrity": "sha512-BnVR1CpKiuD0iobHPaM1iLvcwPYN2uVFAqoLVSpEDKWuOikoCv5HbKLxclhKYUXlWkX86DoZGtqI4XhbOsyrMg==",
             "requires": {
                 "@babel/helper-annotate-as-pure": "^7.22.5",
-                "@babel/helper-create-class-features-plugin": "^7.22.5",
+                "@babel/helper-create-class-features-plugin": "^7.22.9",
                 "@babel/helper-plugin-utils": "^7.22.5",
                 "@babel/plugin-syntax-typescript": "^7.22.5"
             },
@@ -1561,12 +1564,12 @@
             }
         },
         "@babel/preset-env": {
-            "version": "7.22.7",
-            "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.22.7.tgz",
-            "integrity": "sha512-1whfDtW+CzhETuzYXfcgZAh8/GFMeEbz0V5dVgya8YeJyCU6Y/P2Gnx4Qb3MylK68Zu9UiwUvbPMPTpFAOJ+sQ==",
+            "version": "7.22.9",
+            "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.22.9.tgz",
+            "integrity": "sha512-wNi5H/Emkhll/bqPjsjQorSykrlfY5OWakd6AulLvMEytpKasMVUpVy8RL4qBIBs5Ac6/5i0/Rv0b/Fg6Eag/g==",
             "requires": {
-                "@babel/compat-data": "^7.22.6",
-                "@babel/helper-compilation-targets": "^7.22.6",
+                "@babel/compat-data": "^7.22.9",
+                "@babel/helper-compilation-targets": "^7.22.9",
                 "@babel/helper-plugin-utils": "^7.22.5",
                 "@babel/helper-validator-option": "^7.22.5",
                 "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.22.5",
@@ -1640,11 +1643,11 @@
                 "@babel/plugin-transform-unicode-sets-regex": "^7.22.5",
                 "@babel/preset-modules": "^0.1.5",
                 "@babel/types": "^7.22.5",
-                "@nicolo-ribaudo/semver-v6": "^6.3.3",
                 "babel-plugin-polyfill-corejs2": "^0.4.4",
                 "babel-plugin-polyfill-corejs3": "^0.8.2",
                 "babel-plugin-polyfill-regenerator": "^0.5.1",
-                "core-js-compat": "^3.31.0"
+                "core-js-compat": "^3.31.0",
+                "semver": "^6.3.1"
             },
             "dependencies": {
                 "@babel/helper-plugin-utils": {
@@ -1652,10 +1655,10 @@
                     "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz",
                     "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg=="
                 },
-                "@nicolo-ribaudo/semver-v6": {
-                    "version": "6.3.3",
-                    "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/semver-v6/-/semver-v6-6.3.3.tgz",
-                    "integrity": "sha512-3Yc1fUTs69MG/uZbJlLSI3JISMn2UV2rg+1D/vROUqZyh3l6iYHCs7GMp+M40ZD7yOdDbYjJcU1oTJhrc+dGKg=="
+                "semver": {
+                    "version": "6.3.1",
+                    "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+                    "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
                 }
             }
         },
@@ -6195,9 +6198,9 @@
             }
         },
         "browndash-components": {
-            "version": "0.0.62",
-            "resolved": "https://registry.npmjs.org/browndash-components/-/browndash-components-0.0.62.tgz",
-            "integrity": "sha512-lhIuqOylZF7y4ZQXOdTim2r8Et61AaUROl5UYaooCObHvjJb7WIGpFv9B1RQjlbg8vUJ4jeM3e3qb++Cf6ajPg==",
+            "version": "0.0.76",
+            "resolved": "https://registry.npmjs.org/browndash-components/-/browndash-components-0.0.76.tgz",
+            "integrity": "sha512-2ZrDNGxbXnmqRSBifCn6+czz/LqeuyZwSsnRj73Wmo9OOKvYIneGZE17/aFkAl76rXdVmZCcfBdKKBcwEYwNHQ==",
             "requires": {
                 "@emotion/react": "^11.11.1",
                 "@emotion/styled": "^11.11.0",
@@ -6211,9 +6214,9 @@
             },
             "dependencies": {
                 "@babel/cli": {
-                    "version": "7.22.6",
-                    "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.22.6.tgz",
-                    "integrity": "sha512-Be3/RfEDmkMRGT1+ru5nTkfcvWz5jDOYg1V9rXqTz2u9Qt96O1ryboGvxVBp7wOnYWDB8DNHIWb6DThrpudfOw==",
+                    "version": "7.22.9",
+                    "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.22.9.tgz",
+                    "integrity": "sha512-nb2O7AThqRo7/E53EGiuAkMaRbb7J5Qp3RvN+dmua1U+kydm0oznkhqbTEG15yk26G/C3yL6OdZjzgl+DMXVVA==",
                     "requires": {
                         "@jridgewell/trace-mapping": "^0.3.17",
                         "@nicolo-ribaudo/chokidar-2": "2.1.8-no-fsevents.3",
@@ -6642,9 +6645,9 @@
                     "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g=="
                 },
                 "postcss": {
-                    "version": "8.4.25",
-                    "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.25.tgz",
-                    "integrity": "sha512-7taJ/8t2av0Z+sQEvNzCkpDynl0tX3uJMCODi6nT3PfASC7dYCWV9aQ+uiCf+KBD4SEFcu+GvJdGdwzQ6OSjCw==",
+                    "version": "8.4.26",
+                    "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.26.tgz",
+                    "integrity": "sha512-jrXHFF8iTloAenySjM/ob3gSj7pCu0Ji49hnjqzsgSRa50hkWCKD0HQ+gMNJkW38jBI68MpAAg7ZWwHwX8NMMw==",
                     "requires": {
                         "nanoid": "^3.3.6",
                         "picocolors": "^1.0.0",
@@ -6676,9 +6679,9 @@
                     "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A=="
                 },
                 "styled-components": {
-                    "version": "6.0.3",
-                    "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.0.3.tgz",
-                    "integrity": "sha512-qEyWvDK4CYCyDckNIruRJIcQSvcUR3dVEw/fwxu1v0LFzUMPr2uf5PhXHp17FkGK+S4TkglOS+XIealo1MssQA==",
+                    "version": "6.0.4",
+                    "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.0.4.tgz",
+                    "integrity": "sha512-lRJt4vg8hKJhlVG+VKz8QEqPCXKyTryZZ59odyK0UC0HHV3u/mshWTfSay8NpkN0Xijw1iN9r0Leld3dcCcp/w==",
                     "requires": {
                         "@babel/cli": "^7.21.0",
                         "@babel/core": "^7.21.0",
@@ -8156,16 +8159,6 @@
             "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=",
             "dev": true
         },
-        "d": {
-            "version": "1.0.1",
-            "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz",
-            "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==",
-            "dev": true,
-            "requires": {
-                "es5-ext": "^0.10.50",
-                "type": "^1.0.1"
-            }
-        },
         "d3": {
             "version": "7.8.4",
             "resolved": "https://registry.npmjs.org/d3/-/d3-7.8.4.tgz",
@@ -9546,28 +9539,6 @@
                 "is-symbol": "^1.0.2"
             }
         },
-        "es5-ext": {
-            "version": "0.10.62",
-            "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz",
-            "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==",
-            "dev": true,
-            "requires": {
-                "es6-iterator": "^2.0.3",
-                "es6-symbol": "^3.1.3",
-                "next-tick": "^1.1.0"
-            }
-        },
-        "es6-iterator": {
-            "version": "2.0.3",
-            "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
-            "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==",
-            "dev": true,
-            "requires": {
-                "d": "1",
-                "es5-ext": "^0.10.35",
-                "es6-symbol": "^3.1.1"
-            }
-        },
         "es6-promise": {
             "version": "3.2.1",
             "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.2.1.tgz",
@@ -9579,7 +9550,6 @@
             "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==",
             "dev": true,
             "requires": {
-                "d": "^1.0.1",
                 "ext": "^1.1.2"
             }
         },
@@ -25311,12 +25281,6 @@
             "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
             "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
         },
-        "type": {
-            "version": "1.2.0",
-            "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz",
-            "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==",
-            "dev": true
-        },
         "type-check": {
             "version": "0.4.0",
             "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
diff --git a/package.json b/package.json
index b137ddd67..e301268dd 100644
--- a/package.json
+++ b/package.json
@@ -177,7 +177,7 @@
         "body-parser": "^1.19.2",
         "bootstrap": "^4.6.1",
         "brotli": "^1.3.3",
-        "browndash-components": "0.0.62",
+        "browndash-components": "0.0.76",
         "browser-assert": "^1.2.1",
         "bson": "^4.6.1",
         "canvas": "^2.9.3",
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 934803c16..c925cff0f 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -34,7 +34,7 @@ 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/button/FontIconBox';
+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';
@@ -324,8 +324,9 @@ export class DocumentOptions {
     badgeValue?: ScriptField;
 
     //LINEAR VIEW
-    linearView_IsExpanded?: BOOLt = new BoolInfo('is linear view expanded');
+    linearView_IsOpen?: BOOLt = new BoolInfo('is linear view open');
     linearView_Expandable?: BOOLt = new BoolInfo('can linear view be expanded');
+    linearView_Dropdown?: BOOLt = new BoolInfo('can linear view be opened as a dropdown');
     linearView_SubMenu?: BOOLt = new BoolInfo('is doc a sub menu of more linear views');
     flexGap?: NUMt = new NumInfo('Linear view flex gap');
     flexDirection?: 'unset' | 'row' | 'column' | 'row-reverse' | 'column-reverse';
@@ -406,6 +407,7 @@ export class DocumentOptions {
 
     clipboard?: Doc;
     hoverBackgroundColor?: string; // background color of a label when hovered
+    userBackgroundColor?: STRt = new StrInfo('background color associated with a Dash user (seen in header fields of shared documents)');
     userColor?: STRt = new StrInfo('color associated with a Dash user (seen in header fields of shared documents)');
 }
 export namespace Docs {
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 32229f22f..cde3daf5a 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -12,7 +12,7 @@ import { Cast, DateCast, DocCast, StrCast } from "../../fields/Types";
 import { nullAudio } from "../../fields/URLField";
 import { SetCachedGroups, SharingPermissions } from "../../fields/util";
 import { GestureUtils } from "../../pen-gestures/GestureUtils";
-import { OmitKeys, Utils } from "../../Utils";
+import { OmitKeys, Utils, addStyleSheetRule } from "../../Utils";
 import { DocServer } from "../DocServer";
 import { Docs, DocumentOptions, DocUtils, FInfo } from "../documents/Documents";
 import { CollectionViewType, DocumentType } from "../documents/DocumentTypes";
@@ -20,7 +20,7 @@ import { TreeViewType } from "../views/collections/CollectionTreeView";
 import { DashboardView } from "../views/DashboardView";
 import { Colors } from "../views/global/globalEnums";
 import { MainView } from "../views/MainView";
-import { ButtonType } from "../views/nodes/button/FontIconBox";
+import { ButtonType } from "../views/nodes/FontIconBox/FontIconBox";
 import { OpenWhere } from "../views/nodes/DocumentView";
 import { OverlayView } from "../views/OverlayView";
 import { DragManager, dropActionType } from "./DragManager";
@@ -28,7 +28,7 @@ import { MakeTemplate } from "./DropConverter";
 import { FollowLinkScript } from "./LinkFollower";
 import { LinkManager } from "./LinkManager";
 import { ScriptingGlobals } from "./ScriptingGlobals";
-import { ColorScheme } from "./SettingsManager";
+import { ColorScheme, SettingsManager } from "./SettingsManager";
 import { UndoManager } from "./UndoManager";
 
 interface Button {
@@ -373,7 +373,7 @@ export class CurrentUserUtils {
         });
 
         const reqdStackOpts:DocumentOptions ={
-            title: "menuItemPanel", childDragAction: "same", backgroundColor: Colors.DARK_GRAY, layout_boxShadow: "rgba(0,0,0,0)",  dontRegisterView: true, ignoreClick: true,
+            title: "menuItemPanel", childDragAction: "same", layout_boxShadow: "rgba(0,0,0,0)",  dontRegisterView: true, ignoreClick: true,
             _chromeHidden: true, _gridGap: 0, _yMargin: 0, _yPadding: 0, _xMargin: 0, _layout_autoHeight: false, _width: 60, _columnWidth: 60, _lockedPosition: true, isSystem: true,
         };
         return DocUtils.AssignDocField(doc, field, (opts, items) => Docs.Create.StackingDocument(items??[], opts), reqdStackOpts, menuBtns, { dropConverter: "convertToButtons(dragData)" });
@@ -609,7 +609,7 @@ export class CurrentUserUtils {
         const btns = btnDescs.map(desc => dockBtn({_width: 30, _height: 30, defaultDoubleClick: 'ignore', undoIgnoreFields: new List<string>(['opacity']), _dragOnlyWithinContainer: true, ...desc.opts}, desc.scripts));
         const dockBtnsReqdOpts:DocumentOptions = {
             title: "docked buttons", _height: 40, flexGap: 0, layout_boxShadow: "standard", childDragAction: 'move',
-            childDontRegisterViews: true, linearView_IsExpanded: true, linearView_Expandable: true, ignoreClick: true
+            childDontRegisterViews: true, linearView_IsOpen: true, linearView_Expandable: true, ignoreClick: true
         };
         reaction(() => UndoManager.redoStack.slice(), () => Doc.GetProto(btns.find(btn => btn.title === "Redo")!).opacity = UndoManager.CanRedo() ? 1 : 0.4, { fireImmediately: true });
         reaction(() => UndoManager.undoStack.slice(), () => Doc.GetProto(btns.find(btn => btn.title === "Undo")!).opacity = UndoManager.CanUndo() ? 1 : 0.4, { fireImmediately: true });
@@ -625,12 +625,12 @@ export class CurrentUserUtils {
     }
     static viewTools(): Button[] {
         return [
-            { title: "Snap\xA0Lines", icon: "th",           toolTip: "Show Snap Lines",     btnType: ButtonType.ToggleButton, expertMode: false, toolType:"snaplines",  funcs: {}, scripts: { onClick: 'showFreeform(self.toolType, _readOnly_)'}}, // Only when floating document is selected in freeform
-            { title: "Grid",          icon: "border-all",   toolTip: "Show Grid",           btnType: ButtonType.ToggleButton, expertMode: false, toolType:"grid",       funcs: {}, scripts: { onClick: 'showFreeform(self.toolType, _readOnly_)'}}, // Only when floating document is selected in freeform
-            { title: "View\xA0All",   icon: "object-group", toolTip: "Fit all Docs to View",btnType: ButtonType.ToggleButton, expertMode: false, toolType:"viewAll",    funcs: {}, scripts: { onClick: 'showFreeform(self.toolType, _readOnly_)'}}, // Only when floating document is selected in freeform
-            { title: "Clusters",      icon: "braille",      toolTip: "Show Doc Clusters",   btnType: ButtonType.ToggleButton, expertMode: false, toolType:"clusters",   funcs: {}, scripts: { onClick: 'showFreeform(self.toolType, _readOnly_)'}}, // Only when floating document is selected in freeform
-            { title: "Cards",         icon: "brain",        toolTip: "Flashcards",          btnType: ButtonType.ToggleButton, expertMode: false, toolType:"flashcards", funcs: {}, scripts: { onClick: 'showFreeform(self.toolType, _readOnly_)'}}, // Only when floating document is selected in freeform
-            { title: "Arrange",icon:"arrow-down-short-wide",toolTip:"Toggle Auto Arrange",  btnType: ButtonType.ToggleButton, expertMode: false, toolType:"arrange",    funcs: {hidden: 'IsNoviceMode()'}, scripts: { onClick: 'showFreeform(self.toolType, _readOnly_)'}}, // Only when floating document is selected in freeform
+            { title: "Snap", icon: "th",           toolTip: "Show Snap Lines",     btnType: ButtonType.ToggleButton, expertMode: false, toolType:"snaplines",  funcs: {}, scripts: { onClick: '{ return showFreeform(self.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform
+            { title: "Grid",          icon: "border-all",   toolTip: "Show Grid",           btnType: ButtonType.ToggleButton, expertMode: false, toolType:"grid",       funcs: {}, scripts: { onClick: '{ return showFreeform(self.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform
+            { title: "View All",   icon: "object-group", toolTip: "Fit all Docs to View",btnType: ButtonType.ToggleButton, expertMode: false, toolType:"viewAll",    funcs: {}, scripts: { onClick: '{ return showFreeform(self.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform
+            { title: "Clusters",      icon: "braille",      toolTip: "Show Doc Clusters",   btnType: ButtonType.ToggleButton, expertMode: false, toolType:"clusters",   funcs: {}, scripts: { onClick: '{ return showFreeform(self.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform
+            { title: "Cards",         icon: "brain",        toolTip: "Flashcards",          btnType: ButtonType.ToggleButton, expertMode: false, toolType:"flashcards", funcs: {}, scripts: { onClick: '{ return showFreeform(self.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform
+            { title: "Arrange",icon:"arrow-down-short-wide",toolTip:"Toggle Auto Arrange",  btnType: ButtonType.ToggleButton, expertMode: false, toolType:"arrange",    funcs: {hidden: 'IsNoviceMode()'}, scripts: { onClick: '{ return showFreeform(self.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform
         ]
     }
     static textTools():Button[] {
@@ -645,9 +645,13 @@ export class CurrentUserUtils {
             { title: "Under",    toolTip: "Underline (Ctrl+U)",   btnType: ButtonType.ToggleButton, icon: "underline",   toolType:"underline",                     scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} },
             { title: "Bullets",  toolTip: "Bullet List",          btnType: ButtonType.ToggleButton, icon: "list",        toolType:"bullet",                        scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} },
             { title: "#",        toolTip: "Number List",          btnType: ButtonType.ToggleButton, icon: "list-ol",     toolType:"decimal",                       scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} },
-            { title: "Left",     toolTip: "Left align (Cmd-[)",   btnType: ButtonType.ToggleButton, icon: "align-left",  toolType:"left",                          scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}' }},
-            { title: "Center",   toolTip: "Center align (Cmd-\\)",btnType: ButtonType.ToggleButton, icon: "align-center",toolType:"center",                        scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} },
-            { title: "Right",    toolTip: "Right align (Cmd-])",  btnType: ButtonType.ToggleButton, icon: "align-right", toolType:"right",                         scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} },
+            { title: "Alignment",toolTip: "Alignment",            btnType: ButtonType.MultiToggleButton,                  toolType:"alignment", ignoreClick: true,  scripts: {script:  '{ return setFontAttr(self.toolType, value, _readOnly_);}'},
+              subMenu: [
+                { title: "Left",     toolTip: "Left align (Cmd-[)",   btnType: ButtonType.ToggleButton, icon: "align-left",  toolType:"left",                          scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}' }},
+                { title: "Center",   toolTip: "Center align (Cmd-\\)",btnType: ButtonType.ToggleButton, icon: "align-center",toolType:"center",                        scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} },
+                { title: "Right",    toolTip: "Right align (Cmd-])",  btnType: ButtonType.ToggleButton, icon: "align-right", toolType:"right",                         scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} },
+              ]
+            },
             { title: "Dictate",  toolTip: "Dictate",              btnType: ButtonType.ToggleButton, icon: "microphone",  toolType:"dictation",                     scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'}},
             { title: "NoLink",   toolTip: "Auto Link",            btnType: ButtonType.ToggleButton, icon: "link",        toolType:"noAutoLink", expertMode:true,   scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'}, funcs: {hidden: 'IsNoviceMode()'}},
             // { title: "Strikethrough", tooltip: "Strikethrough", btnType: ButtonType.ToggleButton, icon: "strikethrough", scripts: {onClick:: 'toggleStrikethrough()'}},
@@ -695,17 +699,17 @@ export class CurrentUserUtils {
               title: "Perspective",                    toolTip: "View",                 btnType: ButtonType.DropdownList,                                                                                                                                    ignoreClick: true, width: 100, scripts: { script: 'setView(value, _readOnly_)'}},
             { title: "Pin",     icon: "map-pin",       toolTip: "Pin View to Trail",    btnType: ButtonType.ClickButton,         expertMode: false,                                                                                                                             width: 30,  scripts: { onClick: 'pinWithView(altKey)'}},
             { title: "Fill",    icon: "fill-drip",     toolTip: "Background Fill Color",btnType: ButtonType.ColorButton,         expertMode: false,                                                                                                          ignoreClick: true, width: 30,  scripts: { script:  'return setBackgroundColor(value, _readOnly_)'}}, // Only when a document is selected
-            { title: "Header",  icon: "heading",       toolTip: "Header Color",         btnType: ButtonType.ColorButton,         expertMode: false,                                                                                                          ignoreClick: true,             scripts: { script:  'return setHeaderColor(value, _readOnly_)'}},
-            { title: "Overlay", icon: "layer-group",   toolTip: "Overlay",              btnType: ButtonType.ToggleButton,        expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(self.toolType, self.expertMode, true)'},       scripts: { onClick: 'toggleOverlay(_readOnly_)'}}, // Only when floating document is selected in freeform
+            { title: "Header",  icon: "heading",       toolTip: "Header Color",         btnType: ButtonType.ColorButton,         expertMode: true,                                                                                                          ignoreClick: true,             scripts: { script:  'return setHeaderColor(value, _readOnly_)'}},
+            { title: "Overlay", icon: "layer-group",   toolTip: "Overlay",              btnType: ButtonType.ToggleButton,        expertMode: true, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(self.toolType, self.expertMode, true)'},       scripts: { onClick: 'return { toggleOverlay(_readOnly_); }'}}, // Only when floating document is selected in freeform
             { title: "Back",    icon: "chevron-left",  toolTip: "Prev Animation Frame", btnType: ButtonType.ClickButton,         expertMode: true,  toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(self.toolType, self.expertMode)'}, width: 30,  scripts: { onClick: 'prevKeyFrame(_readOnly_)'}},
             { title: "Num",     icon:"",               toolTip: "Frame Number (click to toggle edit mode)",    btnType: ButtonType.TextButton,          expertMode: true,  toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(self.toolType, self.expertMode)', buttonText: 'selectedDocs()?.lastElement()?.currentFrame?.toString()'}, width: 20, scripts: { onClick: '{ return curKeyFrame(_readOnly_);}'}},
             { title: "Fwd",     icon: "chevron-right", toolTip: "Next Animation Frame", btnType: ButtonType.ClickButton,         expertMode: true,  toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(self.toolType, self.expertMode)'}, width: 30,  scripts: { onClick: 'nextKeyFrame(_readOnly_)'}},
-            { title: "Text",    icon: "Text",          toolTip: "Text functions",       subMenu: CurrentUserUtils.textTools(),   expertMode: false, toolType:DocumentType.RTF,            funcs: {                                                                             linearView_IsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Always available
-            { title: "Ink",     icon: "Ink",           toolTip: "Ink functions",        subMenu: CurrentUserUtils.inkTools(),    expertMode: false, toolType:DocumentType.INK,            funcs: {                                                                             linearView_IsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`}, scripts: { onClick: 'setInkToolDefaults()'} }, // Always available
-            { title: "Doc",     icon: "Doc",           toolTip: "Freeform Doc tools",   subMenu: CurrentUserUtils.freeTools(),   expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode, true)`, linearView_IsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Always available
-            { title: "View",    icon: "View",          toolTip: "View tools",           subMenu: CurrentUserUtils.viewTools(),   expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode)`, linearView_IsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Always available
-            { title: "Web",     icon: "Web",           toolTip: "Web functions",        subMenu: CurrentUserUtils.webTools(),    expertMode: false, toolType:DocumentType.WEB,            funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode)`, linearView_IsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Only when Web is selected
-            { title: "Schema",  icon: "Schema",linearBtnWidth:58,toolTip: "Schema functions",subMenu: CurrentUserUtils.schemaTools(), expertMode: false, toolType:CollectionViewType.Schema,   funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode)`, linearView_IsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} } // Only when Schema is selected
+            { title: "Text",    icon: "Text",          toolTip: "Text functions",       subMenu: CurrentUserUtils.textTools(),   expertMode: false, toolType:DocumentType.RTF,            funcs: {                                                                             linearView_IsOpen: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Always available
+            { title: "Ink",     icon: "Ink",           toolTip: "Ink functions",        subMenu: CurrentUserUtils.inkTools(),    expertMode: false, toolType:DocumentType.INK,            funcs: {                                                                             linearView_IsOpen: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`}, scripts: { onClick: 'setInkToolDefaults()'} }, // Always available
+            { title: "Doc",     icon: "Doc",           toolTip: "Freeform Doc tools",   subMenu: CurrentUserUtils.freeTools(),   expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode, true)`, linearView_IsOpen: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Always available
+            { title: "View",    icon: "View",          toolTip: "View tools",           subMenu: CurrentUserUtils.viewTools(),   expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Always available
+            { title: "Web",     icon: "Web",           toolTip: "Web functions",        subMenu: CurrentUserUtils.webTools(),    expertMode: false, toolType:DocumentType.WEB,            funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Only when Web is selected
+            { title: "Schema",  icon: "Schema",linearBtnWidth:58,toolTip: "Schema functions",subMenu: CurrentUserUtils.schemaTools(), expertMode: false, toolType:CollectionViewType.Schema,   funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} } // Only when Schema is selected
         ];
     }
 
@@ -713,7 +717,6 @@ export class CurrentUserUtils {
     static setupContextMenuButton(params:Button, btnDoc?:Doc) {
         const reqdOpts:DocumentOptions = {
             ...OmitKeys(params, ["scripts", "funcs", "subMenu"]).omit,
-            backgroundColor: params.backgroundColor ??"transparent", ///  a bit hacky. if an onClick is specified, then assume a toggle uses onClick to get the backgroundColor (see below).  Otherwise, assume a transparent background
             color: Colors.WHITE, isSystem: true,
             _nativeWidth: params.width ?? 30, _width: params.width ?? 30,
             _height: 30, _nativeHeight: 30, linearBtnWidth: params.linearBtnWidth,
@@ -722,21 +725,20 @@ export class CurrentUserUtils {
         };
         const reqdFuncs:{[key:string]:any} = {
             ...params.funcs,
-            backgroundColor: params.btnType === ButtonType.ToggleButton ? params.scripts?.onClick:undefined /// a bit hacky.  if onClick is set, then we assume it returns a color value when queried with '_readOnly_'.  This will be true for toggle buttons, but not generally
         }
         return DocUtils.AssignScripts(DocUtils.AssignOpts(btnDoc, reqdOpts) ?? Docs.Create.FontIconDocument(reqdOpts), params.scripts, reqdFuncs);
     }
 
     /// Initializes all the default buttons for the top bar context menu
     static setupContextMenuButtons(doc: Doc, field="myContextMenuBtns") {
-        const reqdCtxtOpts:DocumentOptions = { title: "context menu buttons", undoIgnoreFields:new List<string>(['width', "linearView_IsExpanded"]), flexGap: 0, childDragAction: 'embed', childDontRegisterViews: true,  linearView_IsExpanded: true, ignoreClick: true, linearView_Expandable: false, _height: 35 };
+        const reqdCtxtOpts:DocumentOptions = { title: "context menu buttons", undoIgnoreFields:new List<string>(['width', "linearView_IsOpen"]), flexGap: 0, childDragAction: 'embed', childDontRegisterViews: true,  linearView_IsOpen: true, ignoreClick: true, linearView_Expandable: false, _height: 35 };
         const ctxtMenuBtnsDoc = DocUtils.AssignDocField(doc, field, (opts, items) => this.linearButtonList(opts, items??[]), reqdCtxtOpts, undefined);
         const ctxtMenuBtns = CurrentUserUtils.contextMenuTools().map(params => {
             const menuBtnDoc = DocListCast(ctxtMenuBtnsDoc?.data).find(doc => doc.title === params.title);
-            if (!params.subMenu) {
+            if (!params.subMenu) { // button does not have a sub menu
                 return this.setupContextMenuButton(params, menuBtnDoc);
-            } else {
-                const reqdSubMenuOpts = { ...OmitKeys(params, ["scripts", "funcs", "subMenu"]).omit, undoIgnoreFields: new List<string>(['width', "linearView_IsExpanded"]),
+            } else { // linear view
+                const reqdSubMenuOpts = { ...OmitKeys(params, ["scripts", "funcs", "subMenu"]).omit, undoIgnoreFields: new List<string>(['width', "linearView_IsOpen"]),
                     childDontRegisterViews: true, flexGap: 0, _height: 30, ignoreClick: params.scripts?.onClick ? false : true,
                     linearView_SubMenu: true, linearView_Expandable: true, };
                 const items = params.subMenu?.map(sub =>
@@ -847,6 +849,11 @@ export class CurrentUserUtils {
         doc.fontHighlight ?? (doc.fontHighlight = "");
         doc.defaultAclPrivate ?? (doc.defaultAclPrivate = false);
         doc.savedFilters ?? (doc.savedFilters = new List<Doc>());
+        doc.userBackgroundColor ?? (doc.userBackgroundColor = Colors.DARK_GRAY);
+        addStyleSheetRule(SettingsManager._settingsStyle, 'lm_header', { background: `${doc.userBackgroundColor} !important` });
+        doc.userVariantColor ?? (doc.userVariantColor = Colors.MEDIUM_BLUE);
+        doc.userColor ?? (doc.userColor = Colors.LIGHT_GRAY);
+        doc.userTheme ?? (doc.userTheme = ColorScheme.Dark);
         doc.filterDocCount = 0;
         doc.treeViewFreezeChildren = "remove|add";
         this.setupLinkDocs(doc, linkDatabaseId);
diff --git a/src/client/util/DropConverter.ts b/src/client/util/DropConverter.ts
index 47997cc5c..f235be192 100644
--- a/src/client/util/DropConverter.ts
+++ b/src/client/util/DropConverter.ts
@@ -9,7 +9,7 @@ import { RichTextField } from '../../fields/RichTextField';
 import { ImageField } from '../../fields/URLField';
 import { ScriptingGlobals } from './ScriptingGlobals';
 import { listSpec } from '../../fields/Schema';
-import { ButtonType } from '../views/nodes/button/FontIconBox';
+import { ButtonType } from '../views/nodes/FontIconBox/FontIconBox';
 
 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/ReportManager.tsx b/src/client/util/ReportManager.tsx
index 4c1020455..89c17e42f 100644
--- a/src/client/util/ReportManager.tsx
+++ b/src/client/util/ReportManager.tsx
@@ -11,7 +11,7 @@ import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager
 import { DocServer } from '../DocServer';
 import { Networking } from '../Network';
 import { MainViewModal } from '../views/MainViewModal';
-import { FontIconBox } from '../views/nodes/button/FontIconBox';
+import { FontIconBox } from '../views/nodes/FontIconBox/FontIconBox';
 import { DragManager } from './DragManager';
 import { GroupManager } from './GroupManager';
 import './SettingsManager.scss';
@@ -290,7 +290,7 @@ export class ReportManager extends React.Component<{}> {
                 isDisplayed={this.isOpen}
                 interactive={true}
                 closeOnExternalClick={this.close}
-                dialogueBoxStyle={{ width: 'auto', height: '500px', background: Cast(Doc.SharingDoc().userColor, 'string', null) }}
+                dialogueBoxStyle={{ width: 'auto', height: '500px', background: Cast(Doc.UserDoc().userColor, 'string', null) }}
             />
         );
     }
diff --git a/src/client/util/SettingsManager.scss b/src/client/util/SettingsManager.scss
index c41adfdd7..bca649bc3 100644
--- a/src/client/util/SettingsManager.scss
+++ b/src/client/util/SettingsManager.scss
@@ -2,41 +2,20 @@
 
 .settings-interface {
     //background-color: whitesmoke !important;
-    color: grey;
     width: 450px;
-
-    button {
-        background: #315a96;
-        outline: none;
-        border-radius: 5px;
-        border: 0px;
-        color: #fcfbf7;
-        text-transform: uppercase;
-        letter-spacing: 2px;
-        font-size: 75%;
-        padding: 10px;
-        margin: 10px;
-        transition: transform 0.2s;
-        margin: 2px;
-    }
 }
 
 .settings-title {
     font-size: 25px;
     font-weight: bold;
     padding-right: 10px;
-    color: black;
 }
 
 .settings-username {
     font-size: 12px;
     padding-right: 15px;
-    color: black;
     margin-top: 10px;
     margin-bottom: 10px;
-    /* right: 135; */
-    // position: absolute;
-    // left: 243;
 }
 
 .settings-section {
@@ -49,7 +28,6 @@
         font-size: 16;
         font-weight: bold;
         text-align: left;
-        color: black;
         width: 80;
         margin-right: 50px;
     }
@@ -61,45 +39,10 @@
 
 .password-content {
     display: flex;
+    width: 100%;
     flex-direction: column;
     align-items: flex-start;
-
-    .password-content-inputs {
-        display: flex;
-        flex-direction: column;
-        width: 100%;
-        font-size: 10px;
-        align-items: flex-start;
-
-        .password-inputs {
-            border: 1px solid rgb(160, 160, 160);
-            margin-bottom: 15px;
-            width: 130;
-            color: $medium-gray;
-            border-radius: 5px;
-            padding: 7px;
-        }
-    }
-
-    .password-content-buttons {
-        display: flex;
-        gap: 5px;
-        justify-content: center;
-        align-items: flex-start;
-        flex-direction: column;
-
-        .password-submit {
-            //margin-left: 85px;
-            margin-top: 5px;
-        }
-
-        .password-forgot {
-            //margin-left: 65px;
-            //margin-top: -20px;
-            font-size: 12px;
-            white-space: nowrap;
-        }
-    }
+    gap: 5px;
 }
 
 .accounts-content {
@@ -115,7 +58,6 @@
         width: 80%;
         height: 35px;
         margin-right: 10px;
-        color: black;
         border-radius: 5px;
 
         &:hover {
@@ -139,12 +81,6 @@
             }
         }
 
-        .playground-text {
-            color: black;
-            margin-right: 10px;
-            margin-top: 2;
-        }
-
         .acl-text {
             color: black;
             margin-top: 2;
@@ -176,7 +112,6 @@
 
 .appearances-content {
     display: flex;
-    color: black;
     font-size: 10px;
 
     .preferences-color {
@@ -201,7 +136,6 @@
         margin-top: 2px;
 
         .preferences-font-text {
-            color: black;
             margin-top: 4;
             margin-right: 4;
             margin-bottom: 2px;
@@ -216,7 +150,6 @@
 
         .font-select {
             height: 35px;
-            color: black;
             font-size: 9;
             margin-right: 6;
             border-radius: 5px;
@@ -229,7 +162,6 @@
 
         .size-select {
             height: 35px;
-            color: black;
             font-size: 9;
             border-radius: 5px;
             width: 30%;
@@ -241,7 +173,6 @@
     }
 
     .preferences-check {
-        color: black;
         margin-right: 4;
         margin-bottom: -3;
         margin-left: 5;
@@ -265,7 +196,6 @@
 
 
     .settings-content {
-        background: #e4e4e4;
         padding: 10px;
         width: 500px;
         flex: 1 1 auto;
@@ -296,7 +226,6 @@
     }
 
     h1 {
-        color: #121721;
         text-transform: uppercase;
         letter-spacing: 2px;
         font-size: 19;
@@ -325,7 +254,6 @@
 
         .padding {
             padding: 0 0 0 20px;
-            color: black;
         }
     }
 }
@@ -336,16 +264,11 @@
     min-height: 250px;
     height: 100%;
     width: 100%;
-
-    .settings-content {
-        background-color: $off-white;
-    }
 }
 
 .settings-panel {
     position: relative;
     min-width: 150px;
-    background-color: $light-blue;
 
     .settings-user {
         position: absolute;
@@ -370,16 +293,11 @@
 .settings-tabs {
     // font-size: 16px;
     font-weight: 600;
-    color: black;
 
     .tab-control {
         padding: 10px;
         border-bottom: 1px solid #9f9e9e;
         cursor: pointer;
-
-        &.active {
-            background-color: #fdfdfd;
-        }
     }
 }
 
@@ -398,16 +316,18 @@
 
 .tab-content {
     display: flex;
+    flex-flow: row wrap;
+    gap: 10px;
+    overflow: hidden;
 
     .tab-column {
-        flex: 0 0 50%;
+        flex: 0 0 calc(50% - 10px);
         flex-direction: column;
         display: flex;
         justify-content: flex-start;
         align-items: flex-start;
 
         .tab-column-title {
-            color: $dark-gray;
             font-size: 16px;
             font-weight: bold;
             margin-bottom: 10px;
@@ -420,6 +340,7 @@
             align-items: flex-start;
             flex-direction: column;
             gap: 10px;
+            width: 100%;
         }
     }
 }
diff --git a/src/client/util/SettingsManager.tsx b/src/client/util/SettingsManager.tsx
index 09d6d034f..b6df5f26a 100644
--- a/src/client/util/SettingsManager.tsx
+++ b/src/client/util/SettingsManager.tsx
@@ -11,12 +11,12 @@ import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager
 import { DocServer } from '../DocServer';
 import { Networking } from '../Network';
 import { MainViewModal } from '../views/MainViewModal';
-import { FontIconBox } from '../views/nodes/button/FontIconBox';
+import { FontIconBox } from '../views/nodes/FontIconBox/FontIconBox';
 import { DragManager } from './DragManager';
 import { GroupManager } from './GroupManager';
 import './SettingsManager.scss';
 import { undoBatch } from './UndoManager';
-import { Button, ColorPicker, Dropdown, DropdownType, Group, Size, Toggle, ToggleType, Type } from 'browndash-components';
+import { Button, ColorPicker, Dropdown, DropdownType, EditableText, Group, NumberDropdown, Size, Toggle, ToggleType, Type } from 'browndash-components';
 import { BsGoogle } from 'react-icons/bs'
 import { FaFillDrip, FaPalette } from 'react-icons/fa'
 const higflyout = require('@hig/flyout');
@@ -24,9 +24,10 @@ export const { anchorPoints } = higflyout;
 export const Flyout = higflyout.default;
 
 export enum ColorScheme {
-    Dark = '-Dark',
-    Light = '-Light',
-    System = '-MatchSystem',
+    Dark = 'Dark',
+    Light = 'Light',
+    System = 'Match System',
+    Custom = 'Custom'
 }
 
 export enum freeformScrollMode {
@@ -53,8 +54,8 @@ export class SettingsManager extends React.Component<{}> {
     @computed get backgroundColor() {
         return Doc.UserDoc().activeCollectionBackground;
     }
-    @computed get colorScheme() {
-        return Doc.ActiveDashboard?.colorScheme;
+    @computed get userTheme() {
+        return Doc.UserDoc().userTheme;
     }
 
     constructor(props: {}) {
@@ -76,14 +77,31 @@ export class SettingsManager extends React.Component<{}> {
         }
     };
 
+    @computed get userColor() {
+        return StrCast(Doc.UserDoc().userColor)
+    }
+
+    @computed get userVariantColor() {
+        return StrCast(Doc.UserDoc().userVariantColor)
+    }
+
+    @computed get userBackgroundColor() {
+        return StrCast(Doc.UserDoc().userBackgroundColor)
+    }
+
     @undoBatch selectUserMode = action((mode: string) => (Doc.noviceMode = mode === 'Novice'));
     @undoBatch changelayout_showTitle = action((e: React.ChangeEvent) => (Doc.UserDoc().layout_showTitle = (e.currentTarget as any).value ? 'title' : undefined));
     @undoBatch changeFontFamily = action((font: string) => (Doc.UserDoc().fontFamily = font));
     @undoBatch changeFontSize = action((val: number) => (Doc.UserDoc().fontSize = val));
-    @undoBatch switchActiveBackgroundColor = action((color: string) => (Doc.UserDoc().activeCollectionBackground = color));
+    @undoBatch switchUserBackgroundColor = action((color: string) => {
+        Doc.UserDoc().userBackgroundColor = color;
+        addStyleSheetRule(SettingsManager._settingsStyle, 'lm_header', { background: `${color} !important` });
+    });
     @undoBatch switchUserColor = action((color: string) => {
-        Doc.SharingDoc().userColor = undefined;
-        Doc.GetProto(Doc.SharingDoc()).userColor = color;
+        Doc.UserDoc().userColor = color;
+    });
+    @undoBatch switchUserVariantColor = action((color: string) => {
+        Doc.UserDoc().userVariantColor = color;
     });
     @undoBatch playgroundModeToggle = action(() => {
         this.playgroundMode = !this.playgroundMode;
@@ -96,22 +114,24 @@ export class SettingsManager extends React.Component<{}> {
     @undoBatch
     @action
     changeColorScheme = action((scheme: string) => {
-        const activeDashboard = Doc.ActiveDashboard;
-        if (!activeDashboard) return;
+        Doc.UserDoc().userTheme = scheme;
         switch (scheme) {
             case ColorScheme.Light:
-                activeDashboard.colorScheme = ColorScheme.Light
-                addStyleSheetRule(SettingsManager._settingsStyle, 'lm_header', { background: '#d3d3d3 !important' });
+                this.switchUserColor("#323232")
+                this.switchUserBackgroundColor("#DFDFDF")
+                this.switchUserVariantColor("#BDDDF5")
                 break;
             case ColorScheme.Dark:
-                activeDashboard.colorScheme = ColorScheme.Dark;
-                addStyleSheetRule(SettingsManager._settingsStyle, 'lm_header', { background: 'black !important' });
+                this.switchUserColor("#DFDFDF")
+                this.switchUserBackgroundColor("#323232")
+                this.switchUserVariantColor("#4476F7")
+                break;
+            case ColorScheme.Custom:
                 break;
             case ColorScheme.System:
             default:
-                activeDashboard.colorScheme = ColorScheme.System;
                 window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => {
-                    activeDashboard.colorScheme = e.matches ? ColorScheme.Dark : ColorScheme.Light; // undefined means ColorScheme.Light until all CSS is updated with values for each color scheme (e.g., see MainView.scss, DocumentDecorations.scss)
+                    e.matches ? ColorScheme.Dark : ColorScheme.Light; // undefined means ColorScheme.Light until all CSS is updated with values for each color scheme (e.g., see MainView.scss, DocumentDecorations.scss)
                 });
                 break;
         }
@@ -120,18 +140,16 @@ export class SettingsManager extends React.Component<{}> {
     @computed get colorsContent() {
 
 
-        const colorSchemes = [ColorScheme.Light, ColorScheme.Dark, ColorScheme.System];
-        const schemeMap = ['Light', 'Dark', 'Match System'];
-
+        const colorSchemes = [ColorScheme.Light, ColorScheme.Dark, ColorScheme.Custom, ColorScheme.System];
+        const schemeMap = ['Light', 'Dark', 'Custom', 'Match System'];
+        const userTheme = StrCast(Doc.UserDoc().userTheme);
         return (
-            <div className="colors-content">
-                <ColorPicker formLabel='Background Color' icon={<FaFillDrip/>} selectedColor={StrCast(Doc.UserDoc().activeCollectionBackground)} setSelectedColor={this.switchActiveBackgroundColor}/>
-                <ColorPicker formLabel='User Color' icon={<FaPalette/>} selectedColor={StrCast(Doc.SharingDoc().userColor)} setSelectedColor={this.switchUserColor}/>
+            <div style={{width: '100%'}}>
                 <Dropdown 
                     formLabel='Theme'
                     size={Size.SMALL}
                     type={Type.TERT}
-                    selectedVal={StrCast(Doc.ActiveDashboard?.colorScheme)}
+                    selectedVal={userTheme}
                     setSelectedVal={(scheme) => this.changeColorScheme(scheme as string)}
                     items={colorSchemes.map((scheme, i) => (
                         {
@@ -140,8 +158,14 @@ export class SettingsManager extends React.Component<{}> {
                         }
                     ))} 
                     dropdownType={DropdownType.SELECT}
-                    color={StrCast(Doc.SharingDoc().userColor)}
+                    color={this.userColor}
+                    fillWidth
                 />
+                {userTheme === ColorScheme.Custom && <Group formLabel='Custom Theme'>
+                    <ColorPicker tooltip={'User Color'} color={this.userColor} type={Type.SEC} icon={<FaFillDrip/>} selectedColor={this.userColor} setSelectedColor={this.switchUserColor}/>
+                    <ColorPicker tooltip={'User Background Color'} color={this.userColor} type={Type.SEC} icon={<FaPalette/>} selectedColor={this.userBackgroundColor} setSelectedColor={this.switchUserBackgroundColor}/>
+                    <ColorPicker tooltip={'User Variant Color'} color={this.userColor} type={Type.SEC} icon={<FaPalette/>} selectedColor={this.userVariantColor} setSelectedColor={this.switchUserVariantColor}/>
+                </Group>}
             </div>
         );
     }
@@ -155,7 +179,7 @@ export class SettingsManager extends React.Component<{}> {
                     toggleType={ToggleType.SWITCH} 
                     onClick={e => (Doc.UserDoc().layout_showTitle = Doc.UserDoc().layout_showTitle ? undefined : 'author_date')} 
                     toggleStatus={Doc.UserDoc().layout_showTitle !== undefined} size={Size.XSMALL}
-                    color={StrCast(Doc.SharingDoc().userColor)}
+                    color={this.userColor}
 
                 />
                 <Toggle 
@@ -165,7 +189,7 @@ 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={StrCast(Doc.SharingDoc().userColor)}
+                    color={this.userColor}
 
                 />
                 <Toggle 
@@ -175,7 +199,7 @@ export class SettingsManager extends React.Component<{}> {
                     onClick={e => FontIconBox.SetShowLabels(!FontIconBox.GetShowLabels())} 
                     toggleStatus={FontIconBox.GetShowLabels()} 
                     size={Size.XSMALL}
-                    color={StrCast(Doc.SharingDoc().userColor)}
+                    color={this.userColor}
 
                 />
                 <Toggle 
@@ -185,7 +209,7 @@ export class SettingsManager extends React.Component<{}> {
                     onClick={e => FontIconBox.SetRecognizeGestures(!FontIconBox.GetRecognizeGestures())} 
                     toggleStatus={FontIconBox.GetRecognizeGestures()} 
                     size={Size.XSMALL}
-                    color={StrCast(Doc.SharingDoc().userColor)}
+                    color={this.userColor}
 
                 />
                 <Toggle 
@@ -195,7 +219,7 @@ export class SettingsManager extends React.Component<{}> {
                     onClick={e => (Doc.UserDoc().activeInkHideTextLabels = !Doc.UserDoc().activeInkHideTextLabels)} 
                     toggleStatus={BoolCast(Doc.UserDoc().activeInkHideTextLabels)} 
                     size={Size.XSMALL}
-                    color={StrCast(Doc.SharingDoc().userColor)}
+                    color={this.userColor}
 
                 />
                 <Toggle 
@@ -205,7 +229,7 @@ export class SettingsManager extends React.Component<{}> {
                     onClick={e => (Doc.UserDoc().openInkInLightbox = !Doc.UserDoc().openInkInLightbox)} 
                     toggleStatus={BoolCast(Doc.UserDoc().openInkInLightbox)} 
                     size={Size.XSMALL}
-                    color={StrCast(Doc.SharingDoc().userColor)}
+                    color={this.userColor}
 
                 />
             </div>
@@ -238,6 +262,15 @@ 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={() => {}}
+                            />
                             <Dropdown 
                                 items={fontFamilies.map((val) => {
                                     return {
@@ -252,7 +285,8 @@ export class SettingsManager extends React.Component<{}> {
                                 type={Type.TERT}
                                 selectedVal={StrCast(Doc.UserDoc().fontFamily)}
                                 setSelectedVal={(val) => {this.changeFontFamily(val as string)}}
-                                color={StrCast(Doc.SharingDoc().userColor)}
+                                color={this.userColor}
+                                fillWidth
                             />
                         </Group>
                     </div>
@@ -262,8 +296,7 @@ export class SettingsManager extends React.Component<{}> {
     }
 
     @action
-    changeVal = (e: React.ChangeEvent, pass: string) => {
-        const value = (e.target as any).value;
+    changeVal = (value: string, pass: string) => {
         switch (pass) {
             case 'curr':
                 this.curr_password = value;
@@ -280,16 +313,33 @@ export class SettingsManager extends React.Component<{}> {
     @computed get passwordContent() {
         return (
             <div className="password-content">
-                <div className="password-content-inputs">
-                    <input className="password-inputs" type="password" placeholder="current password" onChange={e => this.changeVal(e, 'curr')} />
-                    <input className="password-inputs" type="password" placeholder="new password" onChange={e => this.changeVal(e, 'new')} />
-                    <input className="password-inputs" type="password" placeholder="confirm new password" onChange={e => this.changeVal(e, 'conf')} />
-                </div>
-                <div className="password-content-buttons">
-                    {!this.passwordResultText ? null : <div className={`${this.passwordResultText.startsWith('Error') ? 'error' : 'success'}-text`}>{this.passwordResultText}</div>}
-                    <Button type={Type.SEC} text={'Forgot Password'} color={StrCast(Doc.SharingDoc().userColor)}/>
-                    <Button type={Type.TERT} text={'Submit'} onClick={this.changePassword} color={StrCast(Doc.SharingDoc().userColor)}/>
-                </div>
+                <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
+                />
+                {!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}/>
             </div>
         );
     }
@@ -346,14 +396,15 @@ export class SettingsManager extends React.Component<{}> {
                             dropdownType={DropdownType.SELECT}
                             type={Type.TERT}
                             placement='bottom-start'
-                            color={StrCast(Doc.SharingDoc().userColor)}
+                            color={this.userColor}
+                            fillWidth
                         />
                         <Toggle 
                             formLabel={'Playground Mode'} 
                             toggleType={ToggleType.SWITCH} 
                             toggleStatus={this.playgroundMode} 
                             onClick={this.playgroundModeToggle}
-                            color={StrCast(Doc.SharingDoc().userColor)}
+                            color={this.userColor}
                         />
                     </div>
                     <div className="tab-column-title" style={{ marginTop: 20, marginBottom: 10 }}>
@@ -379,7 +430,7 @@ export class SettingsManager extends React.Component<{}> {
                             dropdownType={DropdownType.SELECT}
                             type={Type.TERT}
                             placement='bottom-start'
-                            color={StrCast(Doc.SharingDoc().userColor)}
+                            color={this.userColor}
                         />
                     </div>
                 </div>
@@ -390,12 +441,12 @@ export class SettingsManager extends React.Component<{}> {
                             text={"Manage Groups"}
                             type={Type.TERT}
                             onClick={() => GroupManager.Instance?.open()}
-                            color={StrCast(Doc.SharingDoc().userColor)}
+                            color={this.userColor}
                         />
                         <Toggle 
                             toggleType={ToggleType.SWITCH} 
                             formLabel={"Default access private"}
-                            color={StrCast(Doc.SharingDoc().userColor)}
+                            color={this.userColor}
                             toggleStatus={BoolCast(Doc.defaultAclPrivate)} 
                             onClick={action(() => (Doc.defaultAclPrivate = !Doc.defaultAclPrivate))}/>
                     </div>
@@ -414,23 +465,35 @@ export class SettingsManager extends React.Component<{}> {
             { title: 'Appearance', ele: this.appearanceContent },
             { title: 'Text', ele: this.textContent },
         ];
-
         return (
             <div className="settings-interface">
-                <div className="settings-panel">
+                <div className="settings-panel" style={{ background: this.userColor }}>
                     <div className="settings-tabs">
-                        {tabs.map(tab => (
-                            <div key={tab.title} className={'tab-control ' + (this.activeTab === tab.title ? 'active' : 'inactive')} onClick={action(() => (this.activeTab = tab.title))}>
-                                {tab.title}
-                            </div>
-                        ))}
+                        {tabs.map(tab => {
+                            const isActive = this.activeTab === tab.title
+                            return (
+                                <div key={tab.title}
+                                    style={{
+                                        background: isActive ? this.userBackgroundColor : this.userColor,
+                                        color: isActive ? this.userColor : this.userBackgroundColor,
+                                    }}
+                                    className={'tab-control ' + (isActive ? 'active' : 'inactive')} 
+                                    onClick={action(() => (this.activeTab = tab.title))
+                                }>
+                                    {tab.title}
+                                </div>
+                            )
+                        })}
                     </div>
 
                     <div className="settings-user">
-                        <div className="settings-username">{Doc.CurrentUserEmail}</div>
+                        <div className="settings-username"
+                            style={{color: this.userBackgroundColor}}
+                        >{Doc.CurrentUserEmail}</div>
                         <Button 
                             text={Doc.GuestDashboard ? 'Exit' : 'Log Out'}
                             type={Type.TERT}
+                            color={this.userVariantColor}
                             onClick={() => window.location.assign(Utils.prepend('/logout'))}
                         />
                     </div>
@@ -439,12 +502,13 @@ export class SettingsManager extends React.Component<{}> {
                             
                 <div className="close-button">
                     <Button
-                        icon={<FontAwesomeIcon icon={'times'} color="black" size={'lg'} />}
+                        icon={<FontAwesomeIcon icon={'times'} size={'lg'} />}
                         onClick={this.close}
+                        color={this.userColor}
                     />
                 </div>
 
-                <div className="settings-content">
+                <div className="settings-content" style={{color: this.userColor, background: this.userBackgroundColor}}>
                     {tabs.map(tab => (
                         <div key={tab.title} className={'tab-section ' + (this.activeTab === tab.title ? 'active' : 'inactive')}>
                             {tab.ele}
@@ -462,7 +526,7 @@ export class SettingsManager extends React.Component<{}> {
                 isDisplayed={this.isOpen}
                 interactive={true}
                 closeOnExternalClick={this.close}
-                dialogueBoxStyle={{ width: 'fit-content', height: '300px', background: Cast(Doc.SharingDoc().userColor, 'string', null) }}
+                dialogueBoxStyle={{ width: 'fit-content', height: '300px', background: Cast(Doc.UserDoc().userColor, 'string', null) }}
             />
         );
     }
diff --git a/src/client/views/AntimodeMenu.scss b/src/client/views/AntimodeMenu.scss
index 8a0e5480e..b205a0f1e 100644
--- a/src/client/views/AntimodeMenu.scss
+++ b/src/client/views/AntimodeMenu.scss
@@ -5,11 +5,15 @@
     position: absolute;
     z-index: 10001;
     height: $antimodemenu-height;
-    background: $dark-gray;
-    border-bottom: $standard-border;
+    width: fit-content;
+    border-radius: $standard-border-radius;
+    overflow: hidden;
     // box-shadow: 3px 3px 3px rgba(0, 0, 0, 0.25);
     // border-radius: 0px 6px 6px 6px;
     display: flex;
+    justify-content: center;
+    align-items: center;
+    gap: 3px;
 
     &.with-rows {
         flex-direction: column
@@ -20,30 +24,6 @@
         height: 35px;
     }
 
-    .antimodeMenu-button {
-        background-color: transparent;
-        width: 35px;
-        height: 35px;
-        padding: 5;
-        text-align: center;
-        display: flex;
-        justify-content: center;
-        align-items: center;
-        position: relative;
-
-        .svg {
-            margin: 0;
-        }
-
-        &.active {
-            background-color: #121212;
-        }
-    }
-
-    .antimodeMenu-button:hover {
-        background-color: rgba(0, 0, 0, 0.4);
-    }
-
     .antimodeMenu-dragger {
         height: 100%;
         transition: width .2s;
diff --git a/src/client/views/AntimodeMenu.tsx b/src/client/views/AntimodeMenu.tsx
index de1207ce4..c41ea7053 100644
--- a/src/client/views/AntimodeMenu.tsx
+++ b/src/client/views/AntimodeMenu.tsx
@@ -1,6 +1,8 @@
 import React = require('react');
 import { observable, action, runInAction } from 'mobx';
 import './AntimodeMenu.scss';
+import { StrCast } from '../../fields/Types';
+import { Doc } from '../../fields/Doc';
 export interface AntimodeMenuProps {}
 
 /**
@@ -148,6 +150,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),
                     transitionProperty: this._transitionProperty,
                     transitionDuration: this._transitionDuration,
                     transitionDelay: this._transitionDelay,
@@ -173,6 +176,7 @@ export abstract class AntimodeMenu<T extends AntimodeMenuProps> extends React.Co
                     height: 'inherit',
                     width: 200,
                     opacity: this._opacity,
+                    background: StrCast(Doc.UserDoc().userBackgroundColor),
                     transitionProperty: this._transitionProperty,
                     transitionDuration: this._transitionDuration,
                     transitionDelay: this._transitionDelay,
@@ -195,6 +199,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),
                     transitionProperty: this._transitionProperty,
                     transitionDuration: this._transitionDuration,
                     transitionDelay: this._transitionDelay,
diff --git a/src/client/views/DashboardView.scss b/src/client/views/DashboardView.scss
index b8a6f6c05..b95312ea0 100644
--- a/src/client/views/DashboardView.scss
+++ b/src/client/views/DashboardView.scss
@@ -14,6 +14,7 @@
             flex-direction: column;
             width: 250px;
             min-width: 250px;
+            gap: 5px;
       }
 
       .all-dashboards {
@@ -56,15 +57,26 @@
     display: flex;
     justify-content: center;
     align-items: center;
+    position: relative;
 
     &:hover {
         color: $light-blue;
         border: solid 2px $light-blue;
     }
+
+    .background {
+        position: absolute;
+        width: 100%;
+        height: 100%;
+        left: 0;
+        top: 0;
+        z-index: -1;
+      }
 }
 
 .dashboard-container {
       border-radius: 10px;
+      position: relative;
       cursor: pointer;
       width: 250px;
       height: 200px;
@@ -99,10 +111,20 @@
       .more {
             z-index: 100;
       }
+
+      .background {
+        position: absolute;
+        width: 100%;
+        height: 100%;
+        left: 0;
+        top: 0;
+        z-index: -1;
+      }
 }
 
 .new-dashboard {
     color: $dark-gray;
+    padding: 10px;
     display: flex;
     width: 100%;
     height: 100%;
diff --git a/src/client/views/DashboardView.tsx b/src/client/views/DashboardView.tsx
index 3bd6ac61c..dd1079d88 100644
--- a/src/client/views/DashboardView.tsx
+++ b/src/client/views/DashboardView.tsx
@@ -1,5 +1,5 @@
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { Button, ColorPicker, FontSize, IconButton, Size, Type } from 'browndash-components';
+import { Button, ColorPicker, EditableText, FontSize, IconButton, Size, Type } from 'browndash-components';
 import { action, computed, observable } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
@@ -24,7 +24,7 @@ import { ContextMenu } from './ContextMenu';
 import './DashboardView.scss';
 import { Colors } from './global/globalEnums';
 import { MainViewModal } from './MainViewModal';
-import { ButtonType } from './nodes/button/FontIconBox';
+import { ButtonType } from './nodes/FontIconBox/FontIconBox';
 import { FaPlus } from 'react-icons/fa';
 
 enum DashboardGroup {
@@ -43,13 +43,16 @@ export class DashboardView extends React.Component {
     @observable private selectedDashboardGroup = DashboardGroup.MyDashboards;
 
     @observable private newDashboardName: string | undefined = undefined;
-    @observable private newDashboardColor: string | undefined = undefined;
+    @observable private newDashboardColor: string | undefined = "#AFAFAF";
     @action abortCreateNewDashboard = () => {
         this.newDashboardName = undefined;
     };
     @action setNewDashboardName(name: string) {
         this.newDashboardName = name;
     }
+    @action setNewDashboardColor(color: string) {
+        this.newDashboardColor = color;
+    }
 
     @action
     selectDashboardGroup = (group: DashboardGroup) => {
@@ -95,23 +98,33 @@ export class DashboardView extends React.Component {
         const dashboardCount = DocListCast(Doc.MyDashboards.data).length + 1;
         const placeholder = `Dashboard ${dashboardCount}`;
         return (
-            <div className="new-dashboard">
+            <div className="new-dashboard"
+                style={{ 
+                    background: StrCast(Doc.UserDoc().userBackgroundColor),
+                    color: StrCast(Doc.UserDoc().userColor)
+                }}
+            >
                 <div className="header">Create New Dashboard</div>
-                <div className="title-input">
-                    Title
-                    <input className="input" placeholder={placeholder} onChange={e => this.setNewDashboardName((e.target as any).value)} />
-                </div>
-                <div className="color-picker">
-                    Background
-                    <ColorPicker
-                        onChange={color => {
-                            this.newDashboardColor = color;
-                        }}
-                    />
-                </div>
+                <EditableText 
+                    formLabel='Title'
+                    placeholder={placeholder}
+                    type={Type.SEC}
+                    color={StrCast(Doc.UserDoc().userColor)}
+                    setVal={val => this.setNewDashboardName(val as string)}
+                    fillWidth
+                />
+                <ColorPicker
+                    formLabel='Background'
+                    colorPickerType='github'
+                    type={Type.TERT}
+                    selectedColor={this.newDashboardColor}
+                    setSelectedColor={color => {
+                        this.setNewDashboardColor(color);
+                    }}
+                />
                 <div className="button-bar">
-                    <Button text="Cancel" onClick={this.abortCreateNewDashboard} />
-                    <Button text="Create" onClick={() => this.createNewDashboard(this.newDashboardName!, this.newDashboardColor)} />
+                    <Button text="Cancel" color={StrCast(Doc.UserDoc().userColor)} onClick={this.abortCreateNewDashboard} />
+                    <Button type={Type.TERT} text="Create" color={StrCast(Doc.UserDoc().userVariantColor)} onClick={() => this.createNewDashboard(this.newDashboardName!, this.newDashboardColor)} />
                 </div>
             </div>
         );
@@ -150,32 +163,49 @@ export class DashboardView extends React.Component {
     };
 
     render() {
+        const color = StrCast(Doc.UserDoc().userColor)
+        const variant = StrCast(Doc.UserDoc().userVariantColor)
         return (
             <>
                 <div className="dashboard-view">
                     <div className="left-menu">
-                        <div className="new-dashboard-button">
-                            <Button icon={<FaPlus />} size={Size.LARGE} text="New" type={Type.SEC} onClick={() => this.setNewDashboardName('')} />
-                        </div>
-                        <div className={`text-button ${this.selectedDashboardGroup === DashboardGroup.MyDashboards && 'selected'}`} onClick={() => this.selectDashboardGroup(DashboardGroup.MyDashboards)}>
-                            My Dashboards
-                        </div>
-                        <div className={`text-button ${this.selectedDashboardGroup === DashboardGroup.SharedDashboards && 'selected'}`} onClick={() => this.selectDashboardGroup(DashboardGroup.SharedDashboards)}>
-                            Shared Dashboards
-                        </div>
+                        <Button 
+                            text={'My Dashboards'}
+                            active={this.selectedDashboardGroup === DashboardGroup.MyDashboards}
+                            color={color}
+                            align={'flex-start'}
+                            onClick={() => this.selectDashboardGroup(DashboardGroup.MyDashboards)}
+                            fillWidth
+                        />
+                        <Button 
+                            text={'Shared Dashboards'}
+                            active={this.selectedDashboardGroup === DashboardGroup.SharedDashboards}
+                            color={color}
+                            align={'flex-start'}
+                            onClick={() => this.selectDashboardGroup(DashboardGroup.SharedDashboards)}
+                            fillWidth
+                        />
+                        <Button icon={<FaPlus />} color={variant} iconPlacement="left" text="New Dashboard" type={Type.TERT} onClick={() => this.setNewDashboardName('')} />
                     </div>
                     <div className="all-dashboards">
                         {this.getDashboards().map(dashboard => {
                             const href = ImageCast(dashboard.thumb)?.url.href;
                             return (
-                                <div className="dashboard-container" key={dashboard[Id]} onContextMenu={e => this.onContextMenu(dashboard, e)} onClick={e => this.clickDashboard(e, dashboard)}>
+                                <div 
+                                    className="dashboard-container" key={dashboard[Id]} 
+                                    onContextMenu={e => this.onContextMenu(dashboard, e)} onClick={e => this.clickDashboard(e, dashboard)}>
                                     <img
                                         src={
                                             href ?? 'https://media.istockphoto.com/photos/hot-air-balloons-flying-over-the-botan-canyon-in-turkey-picture-id1297349747?b=1&k=20&m=1297349747&s=170667a&w=0&h=oH31fJty_4xWl_JQ4OIQWZKP8C6ji9Mz7L4XmEnbqRU='
                                         }
                                     />
                                     <div className="info">
-                                        <input style={{ border: 'unset' }} className="input" onClick={e => e.stopPropagation()} defaultValue={StrCast(dashboard.title)} onChange={e => (Doc.GetProto(dashboard).title = (e.target as any).value)} />
+                                        <EditableText 
+                                            type={Type.PRIM}
+                                            color={color}
+                                            val={StrCast(dashboard.title)} 
+                                            setVal={val => (Doc.GetProto(dashboard).title = val)}
+                                        />
                                         {this.selectedDashboardGroup === DashboardGroup.SharedDashboards && this.isUnviewedSharedDashboard(dashboard) ? <div>unviewed</div> : <div></div>}
                                         <div
                                             className="more"
@@ -188,9 +218,13 @@ export class DashboardView extends React.Component {
                                                 e.stopPropagation();
                                                 this.onContextMenu(dashboard, e);
                                             }}>
-                                            <Button size={Size.SMALL} icon={<FontAwesomeIcon color="black" size="lg" icon="bars" />} />
+                                            <Button size={Size.SMALL} color={color} icon={<FontAwesomeIcon color={color} size="lg" icon="bars" />} />
                                         </div>
                                     </div>
+                                    <div className={`background`} style={{
+                                        background: StrCast(Doc.UserDoc().userColor),
+                                        filter: 'opacity(0.2)'
+                                    }}/>
                                 </div>
                             );
                         })}
@@ -200,6 +234,10 @@ export class DashboardView extends React.Component {
                                 this.setNewDashboardName('');
                             }}>
                             +
+                            <div className={`background`} style={{
+                                background: StrCast(Doc.UserDoc().userColor),
+                                filter: 'opacity(0.2)'
+                            }}/>
                         </div>
                     </div>
                 </div>
diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx
index 7043edcee..4deed5ed9 100644
--- a/src/client/views/EditableView.tsx
+++ b/src/client/views/EditableView.tsx
@@ -6,6 +6,7 @@ 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 {
     /**
@@ -231,39 +232,49 @@ export class EditableView extends React.Component<EditableProps> {
                     onChange: this.props.autosuggestProps.onChange,
                 }}
             />
-        ) : this.props.oneLine !== false && this.props.GetValue()?.toString().indexOf('\n') === -1 ? (
-            <input
-                className="editableView-input"
-                ref={r => (this._inputref = r)}
-                style={{ display: this.props.display, overflow: 'auto', fontSize: this.props.fontSize, minWidth: 20, background: this.props.background }}
-                placeholder={this.props.placeholder}
-                onBlur={e => this.finalizeEdit(e.currentTarget.value, false, true, false)}
-                defaultValue={this.props.GetValue()}
-                autoFocus={true}
-                onChange={this.onChange}
-                onKeyDown={this.onKeyDown}
-                onKeyPress={this.stopPropagation}
-                onPointerDown={this.stopPropagation}
-                onClick={this.stopPropagation}
-                onPointerUp={this.stopPropagation}
+        ) : <EditableText
+                // oneLine={this.props.oneLine && this.props.GetValue()?.toString().indexOf('\n') === -1}
+                editing={true} 
+                onEdit={function (newText: string): void {
+                    throw new Error('Function not implemented.');
+                } } 
+                setEditing={function (editing: boolean): void {
+                    throw new Error('Function not implemented.');
+                } }                
+                // onEdit={this.onChange}
             />
-        ) : (
-            <textarea
-                className="editableView-input"
-                ref={r => (this._inputref = r)}
-                style={{ display: this.props.display, overflow: 'auto', fontSize: this.props.fontSize, minHeight: `min(100%, ${(this.props.GetValue()?.split('\n').length || 1) * 15})`, minWidth: 20, background: this.props.background }}
-                placeholder={this.props.placeholder}
-                onBlur={e => this.finalizeEdit(e.currentTarget.value, false, true, false)}
-                defaultValue={this.props.GetValue()}
-                autoFocus={true}
-                onChange={this.onChange}
-                onKeyDown={this.onKeyDown}
-                onKeyPress={this.stopPropagation}
-                onPointerDown={this.stopPropagation}
-                onClick={this.stopPropagation}
-                onPointerUp={this.stopPropagation}
-            />
-        );
+        //     // <input
+        //     //     className="editableView-input"
+        //     //     ref={r => (this._inputref = r)}
+        //     //     style={{ display: this.props.display, overflow: 'auto', fontSize: this.props.fontSize, minWidth: 20, background: this.props.background }}
+        //     //     placeholder={this.props.placeholder}
+        //     //     onBlur={e => this.finalizeEdit(e.currentTarget.value, false, true, false)}
+        //     //     defaultValue={this.props.GetValue()}
+        //     //     autoFocus={true}
+        //     //     onChange={this.onChange}
+        //     //     onKeyDown={this.onKeyDown}
+        //     //     onKeyPress={this.stopPropagation}
+        //     //     onPointerDown={this.stopPropagation}
+        //     //     onClick={this.stopPropagation}
+        //     //     onPointerUp={this.stopPropagation}
+        //     // />
+        // ) : (
+        //     <textarea
+        //         className="editableView-input"
+        //         ref={r => (this._inputref = r)}
+        //         style={{ display: this.props.display, overflow: 'auto', fontSize: this.props.fontSize, minHeight: `min(100%, ${(this.props.GetValue()?.split('\n').length || 1) * 15})`, minWidth: 20, background: this.props.background }}
+        //         placeholder={this.props.placeholder}
+        //         onBlur={e => this.finalizeEdit(e.currentTarget.value, false, true, false)}
+        //         defaultValue={this.props.GetValue()}
+        //         autoFocus={true}
+        //         onChange={this.onChange}
+        //         onKeyDown={this.onKeyDown}
+        //         onKeyPress={this.stopPropagation}
+        //         onPointerDown={this.stopPropagation}
+        //         onClick={this.stopPropagation}
+        //         onPointerUp={this.stopPropagation}
+        //     />
+        // );
     }
 
     render() {
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index 54ad519de..4e6d5c2e9 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -31,7 +31,7 @@ import {
     SetActiveInkWidth,
 } from './InkingStroke';
 import { InkTranscription } from './InkTranscription';
-import { checkInksToGroup } from './nodes/button/FontIconBox';
+import { checkInksToGroup } from './nodes/FontIconBox/FontIconBox';
 import { DocumentView } from './nodes/DocumentView';
 import { RadialMenu } from './nodes/RadialMenu';
 import { Touchable } from './Touchable';
diff --git a/src/client/views/MainView.scss b/src/client/views/MainView.scss
index b95ce0e99..e33054c8e 100644
--- a/src/client/views/MainView.scss
+++ b/src/client/views/MainView.scss
@@ -68,10 +68,6 @@ h1,
     left: 0;
     z-index: 1;
     touch-action: none;
-
-    .searchBox-container {
-        background: $light-gray;
-    }
 }
 
 .mainView-container,
@@ -118,10 +114,6 @@ h1,
         background: $light-gray;
     }
 
-    .searchBox-container {
-        background: $dark-gray;
-    }
-
     .contextMenu-cont,
     .contextMenu-item {
         background: $dark-gray;
@@ -193,17 +185,6 @@ h1,
             background: $light-gray;
         }
     }
-
-    .propertiesView {
-        left: 0;
-        position: absolute;
-        z-index: 2;
-        background-color: $light-gray;
-
-        .editable-title {
-            background-color: $light-gray;
-        }
-    }
 }
 
 .mainView-libraryHandle {
@@ -250,7 +231,6 @@ h1,
 
 .mainView-leftMenuPanel {
     min-width: var(--menuPanelWidth);
-    background-color: $dark-gray;
     border-right: $standard-border;
 
     .collectionStackingView {
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index ec8f5989f..a7164f88b 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -754,7 +754,8 @@ export class MainView extends React.Component {
 
     @computed get leftMenuPanel() {
         return (
-            <div key="menu" className="mainView-leftMenuPanel" style={{ display: LightboxView.LightboxDoc ? 'none' : undefined }}>
+            <div key="menu" className="mainView-leftMenuPanel" style={{ background: StrCast(Doc.UserDoc().userBackgroundColor),
+                display: LightboxView.LightboxDoc ? 'none' : undefined }}>
                 <DocumentView
                     Document={Doc.MyLeftSidebarMenu}
                     DataDoc={undefined}
@@ -809,8 +810,8 @@ export class MainView extends React.Component {
                 {this._hideUI ? null : this.leftMenuPanel}
                 <div key="inner" className={`mainView-innerContent${this.colorScheme}`}>
                     {this.flyout}
-                    <div className="mainView-libraryHandle" style={{ left: leftMenuFlyoutWidth - 10 /* ~half width of handle */, display: !this._leftMenuFlyoutWidth ? 'none' : undefined }} onPointerDown={this.onFlyoutPointerDown}>
-                        <FontAwesomeIcon icon="chevron-left" color={this.colorScheme === ColorScheme.Dark ? 'white' : 'black'} style={{ opacity: '50%' }} size="sm" />
+                    <div className="mainView-libraryHandle" style={{ background: StrCast(Doc.UserDoc().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" />
                     </div>
                     <div className="mainView-innerContainer" style={{ width: `calc(100% - ${width}px)` }}>
                         {this.dockingContent}
@@ -964,7 +965,11 @@ export class MainView extends React.Component {
     render() {
         return (
             <div
-                className={`mainView-container${this.colorScheme}`}
+                className={`mainView-container ${this.colorScheme}`}
+                style={{
+                    color: StrCast(Doc.UserDoc().userColor),
+                    background: StrCast(Doc.UserDoc().userBackgroundColor),
+                }}
                 onScroll={() => (ele => (ele.scrollTop = ele.scrollLeft = 0))(document.getElementById('root')!)}
                 ref={r => {
                     r &&
diff --git a/src/client/views/MainViewModal.scss b/src/client/views/MainViewModal.scss
index 0648e31c5..4bf9eb79f 100644
--- a/src/client/views/MainViewModal.scss
+++ b/src/client/views/MainViewModal.scss
@@ -4,22 +4,23 @@
     z-index: 10000;
     width: 100%;
     height: 100%;
+    box-shadow: #00000044 5px 5px 10px;
 
     .dialogue-box {
-        padding: 10px;
         position: absolute;
         z-index: 1000;
         text-align: center;
         justify-content: center;
         align-self: center;
         align-content: center;
-        background: white;
         // border-radius: 10px;
         box-shadow: #00000044 5px 5px 10px;
         transform: translate(-50%, -50%);
         top: 50%;
         left: 50%;
         transition: 0.5s all ease;
+        border-radius: 10px;
+        overflow: hidden;
     }
 
     .overlay {
@@ -28,6 +29,7 @@
         position: absolute;
         z-index: 999;
         transition: 0.5s all ease;
+        backdrop-filter: blur(5px);
     }
 
 }
\ No newline at end of file
diff --git a/src/client/views/MainViewModal.tsx b/src/client/views/MainViewModal.tsx
index 32997a944..42df99864 100644
--- a/src/client/views/MainViewModal.tsx
+++ b/src/client/views/MainViewModal.tsx
@@ -1,6 +1,10 @@
 import * as React from 'react';
 import './MainViewModal.scss';
 import { observer } from 'mobx-react';
+import { Doc } from '../../fields/Doc';
+import { StrCast } from '../../fields/Types';
+import { isDark } from 'browndash-components';
+import { Colors } from './global/globalEnums';
 
 export interface MainViewOverlayProps {
     isDisplayed: boolean;
@@ -41,9 +45,8 @@ export class MainViewModal extends React.Component<MainViewOverlayProps> {
                     className="overlay"
                     onClick={this.props?.closeOnExternalClick}
                     style={{
-                        backgroundColor: 'black',
+                        backgroundColor: isDark(StrCast(Doc.UserDoc().userColor)) ? "#DFDFDF30" : "#32323230",
                         ...(p.overlayStyle || {}),
-                        opacity: p.isDisplayed ? overlayOpacity : 0,
                     }}
                 />
             </div>
diff --git a/src/client/views/PropertiesButtons.scss b/src/client/views/PropertiesButtons.scss
index 36b2df73e..db30745fc 100644
--- a/src/client/views/PropertiesButtons.scss
+++ b/src/client/views/PropertiesButtons.scss
@@ -57,14 +57,13 @@ $linkGap : 3px;
 }
 
 .propertiesButtons {
-    margin-top: 3px;
-    grid-column: 1/4;
     width: 100%;
     height: auto;
     display: flex;
     flex-direction: row;
     flex-wrap: wrap;
     padding-bottom: 5.5px;
+    gap: 5px;
 }
 
 .onClickFlyout-editScript {
@@ -81,10 +80,7 @@ $linkGap : 3px;
 .propertiesButtons-button {
     pointer-events: auto;
     padding-right: 5px;
-    width: 25px;
-    border-radius: 5px;
-    margin-right: 20px;
-    margin-bottom: 8px;
+    width: 100%;
 }
 
 .propertiesButton-dropdownList {
diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx
index 74dd1c2f7..3148d9ddd 100644
--- a/src/client/views/PropertiesButtons.tsx
+++ b/src/client/views/PropertiesButtons.tsx
@@ -21,6 +21,7 @@ import { DocumentView, OpenWhere } from './nodes/DocumentView';
 import { pasteImageBitmap } from './nodes/WebBoxRenderer';
 import './PropertiesButtons.scss';
 import React = require('react');
+import { Dropdown, DropdownType, IListItemProps, Toggle, ToggleType, Type } from 'browndash-components';
 const higflyout = require('@hig/flyout');
 export const { anchorPoints } = higflyout;
 export const Flyout = higflyout.default;
@@ -44,24 +45,23 @@ export class PropertiesButtons extends React.Component<{}, {}> {
     propertyToggleBtn = (label: string, property: string, tooltip: (on?: any) => string, icon: (on: boolean) => string, onClick?: (dv: Opt<DocumentView>, doc: Doc, property: string) => void, useUserDoc?: boolean) => {
         const targetDoc = useUserDoc ? Doc.UserDoc() : this.selectedDoc;
         const onPropToggle = (dv: Opt<DocumentView>, doc: Doc, prop: string) => ((dv?.layoutDoc || doc)[prop] = (dv?.layoutDoc || doc)[prop] ? false : true);
-        return !targetDoc ? null : (
-            <Tooltip title={<div className={`dash-tooltip`}>{tooltip(targetDoc?.[property])} </div>} placement="top">
-                <div>
-                    <div
-                        className={`propertiesButtons-linkButton-empty toggle-${StrCast(targetDoc[property]).includes(':hover') ? 'hover' : targetDoc[property] ? 'on' : 'off'}`}
-                        onPointerDown={e => e.stopPropagation()}
-                        onClick={undoable(() => {
-                            if (SelectionManager.Views().length > 1) {
-                                SelectionManager.Views().forEach(dv => (onClick ?? onPropToggle)(dv, dv.rootDoc, property));
-                            } else if (targetDoc) (onClick ?? onPropToggle)(undefined, targetDoc, property);
-                        }, property)}>
-                        <FontAwesomeIcon className="documentdecorations-icon" size="lg" icon={icon(BoolCast(targetDoc?.[property])) as any} />
-                    </div>
-                    <div className="propertiesButtons-title">{label}</div>
-                </div>
-            </Tooltip>
-        );
+        return !targetDoc ? null : <Toggle
+            toggleStatus={BoolCast(targetDoc[property])}
+            text={tooltip(targetDoc?.[property])}
+            color={StrCast(Doc.UserDoc().userColor)}
+            icon={<FontAwesomeIcon className="documentdecorations-icon" size="lg" icon={icon(BoolCast(targetDoc?.[property])) as any} />}
+            iconPlacement={'left'}
+            align={'flex-start'}
+            fillWidth={true}
+            toggleType={ToggleType.BUTTON}
+            onClick={undoable(() => {
+                if (SelectionManager.Views().length > 1) {
+                    SelectionManager.Views().forEach(dv => (onClick ?? onPropToggle)(dv, dv.rootDoc, property));
+                } else if (targetDoc) (onClick ?? onPropToggle)(undefined, targetDoc, property);
+            }, property)}
+        />
     };
+
     @computed get lockButton() {
         return this.propertyToggleBtn(
             'No\xA0Drag',
@@ -244,21 +244,61 @@ export class PropertiesButtons extends React.Component<{}, {}> {
         );
     }
 
+    @computed get onClickVal() {
+        const linkButton = IsFollowLinkScript(this.selectedDoc.onClick);
+        const followLoc = this.selectedDoc._followLinkLocation;
+        const linkedToLightboxView = () => LinkManager.Links(this.selectedDoc).some(link => LinkManager.getOppositeAnchor(link, this.selectedDoc)?._isLightbox);
+
+        if (followLoc === OpenWhere.lightbox && !linkedToLightboxView()) return 'linkInPlace'
+        else if (linkButton && followLoc === OpenWhere.addRight) return 'linkOnRight'
+        else if (linkButton && this.selectedDoc._followLinkLocation === OpenWhere.lightbox && linkedToLightboxView()) return 'enterPortal'
+        else if (ScriptCast(this.selectedDoc.onClick)?.script.originalScript.includes('toggleDetail')) return 'toggleDetail'
+        else return 'nothing'
+    }
+
     @computed
     get onClickButton() {
+        const buttonList = [
+            ['nothing', 'Select Document'],
+            ['enterPortal', 'Enter Portal'],
+            ['toggleDetail', 'Toggle Detail'],
+            ['linkInPlace', 'Open Link in Lightbox'],
+            ['linkOnRight', 'Open Link on Right'],
+        ];
+        
+        const items: IListItemProps[] = buttonList.map(value => {
+            return (
+                {
+                    text: value[1],
+                    val: value[1],
+                }
+            );
+        });
+        console.log("click val: ", this.onClickVal)
         return !this.selectedDoc ? null : (
-            <Tooltip title={<div className="dash-tooltip">Choose onClick behavior</div>} placement="top">
-                <div>
-                    <div className="propertiesButtons-linkFlyout">
-                        <Flyout anchorPoint={anchorPoints.LEFT_TOP} content={this.onClickFlyout}>
-                            <div className={'propertiesButtons-linkButton-empty'} onPointerDown={e => e.stopPropagation()}>
-                                <FontAwesomeIcon className="documentdecorations-icon" icon="mouse-pointer" size="lg" />
-                            </div>
-                        </Flyout>
-                    </div>
-                    <div className="propertiesButtons-title"> onclick </div>
-                </div>
-            </Tooltip>
+            <Dropdown
+                tooltip={'Choose onClick behavior'} 
+                items={items}
+                selectedVal={this.onClickVal}
+                setSelectedVal={(val) => this.handleOptionChange(val as string)}
+                title={'Choose onClick behaviour'}
+                color={StrCast(Doc.UserDoc().userColor)}
+                dropdownType={DropdownType.SELECT}
+                type={Type.SEC}
+                fillWidth
+            />
+            // <Tooltip title={<div className="dash-tooltip">Choose onClick behavior</div>} placement="top">
+            //     <div>
+            //         <div className="propertiesButtons-linkFlyout">
+            //             <Flyout anchorPoint={anchorPoints.LEFT_TOP} content={this.onClickFlyout}>
+            //                 <div className={'propertiesButtons-linkButton-empty'} onPointerDown={e => e.stopPropagation()}>
+            //                     <FontAwesomeIcon className="documentdecorations-icon" icon="mouse-pointer" size="lg" />
+            //                 </div>
+            //             </Flyout>
+            //         </div>
+            //         <div className="propertiesButtons-title"> onclick </div>
+            //     </div>
+            // </Tooltip>
         );
     }
     @computed
diff --git a/src/client/views/PropertiesDocBacklinksSelector.scss b/src/client/views/PropertiesDocBacklinksSelector.scss
index 4d2a61c3b..5c53acf48 100644
--- a/src/client/views/PropertiesDocBacklinksSelector.scss
+++ b/src/client/views/PropertiesDocBacklinksSelector.scss
@@ -1,4 +1,4 @@
-.propertiesView-contexts-content {
+.propertiesDocBacklinksSelector {
     .linkMenu {
         position: relative;
     }
diff --git a/src/client/views/PropertiesDocBacklinksSelector.tsx b/src/client/views/PropertiesDocBacklinksSelector.tsx
index 3e69bcba6..da4438481 100644
--- a/src/client/views/PropertiesDocBacklinksSelector.tsx
+++ b/src/client/views/PropertiesDocBacklinksSelector.tsx
@@ -31,7 +31,7 @@ export class PropertiesDocBacklinksSelector extends React.Component<PropertiesDo
 
     render() {
         return !SelectionManager.Views().length ? null : (
-            <div className="preroptiesDocBacklinksSelector">
+            <div className="propertiesDocBacklinksSelector">
                 {this.props.hideTitle ? null : <p key="contexts">Contexts:</p>}
                 <LinkMenu docView={SelectionManager.Views().lastElement()} clearLinkEditor={undefined} itemHandler={this.getOnClick} style={{ left: 0, top: 0 }} />
             </div>
diff --git a/src/client/views/PropertiesDocContextSelector.tsx b/src/client/views/PropertiesDocContextSelector.tsx
index e1279c9a7..6cac7b0fe 100644
--- a/src/client/views/PropertiesDocContextSelector.tsx
+++ b/src/client/views/PropertiesDocContextSelector.tsx
@@ -53,6 +53,7 @@ export class PropertiesDocContextSelector extends React.Component<PropertiesDocC
     };
 
     render() {
+        if (this._docs.length < 1) return undefined
         return (
             <div>
                 {this.props.hideTitle ? null : <p key="contexts">Contexts:</p>}
diff --git a/src/client/views/PropertiesSection.scss b/src/client/views/PropertiesSection.scss
new file mode 100644
index 000000000..79479a4ce
--- /dev/null
+++ b/src/client/views/PropertiesSection.scss
@@ -0,0 +1,24 @@
+@import './global/globalCssVariables.scss';
+
+.propertiesView-section {
+    
+    .propertiesView-content {
+        padding: 10px;
+    }
+    
+    .propertiesView-sectionTitle {
+        text-align: center;
+        display: flex;
+        padding: 10px;
+        font-size: 14px;
+        font-weight: bold;
+        justify-content: space-between;
+        align-items: center;
+    
+        .propertiesView-sectionTitle-icon {
+            width: 20px;
+            height: 20px;
+            align-items: flex-end;
+        }
+    }
+}
diff --git a/src/client/views/PropertiesSection.tsx b/src/client/views/PropertiesSection.tsx
new file mode 100644
index 000000000..b900d17ca
--- /dev/null
+++ b/src/client/views/PropertiesSection.tsx
@@ -0,0 +1,51 @@
+import React = require('react');
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
+import { action, computed } from "mobx"
+import { observer } from "mobx-react"
+import './PropertiesSection.scss'
+import { Doc } from '../../fields/Doc';
+import { StrCast } from '../../fields/Types';
+
+export interface PropertiesSectionProps {
+    title: string, 
+    content?: JSX.Element | string | null, 
+    isOpen: boolean,
+    setIsOpen: (bool: boolean) => any 
+    inSection?: boolean,
+    setInSection?: (bool: boolean) => any 
+}
+
+@observer
+export class PropertiesSection extends React.Component<PropertiesSectionProps> {
+    @computed get color() {
+        return StrCast(Doc.UserDoc().userColor);
+    }
+
+    @computed get backgroundColor() {
+        return StrCast(Doc.UserDoc().userBackgroundColor);
+    }
+
+    @computed get variantColor() {
+        return StrCast(Doc.UserDoc().userVariantColor);
+    }
+    render() {
+        console.log(this.props.title, this.props.content)
+        if (this.props.content === undefined || this.props.content === null) return null
+        else return <div className="propertiesView-section" onPointerEnter={action(() => (this.props.setInSection && this.props.setInSection(true)))} onPointerLeave={action(() => (this.props.setInSection && this.props.setInSection(false)))}>
+        <div className="propertiesView-sectionTitle" onPointerDown={action(() => (this.props.setIsOpen(!this.props.isOpen)))} style={{ 
+            background: this.props.isOpen ?  this.variantColor : this.backgroundColor,
+            color: this.color
+        }}>
+            {this.props.title}
+            <div className="propertiesView-sectionTitle-icon">
+                <FontAwesomeIcon icon={this.props.isOpen ? 'caret-down' : 'caret-right'} size="lg"  />
+            </div>
+        </div>
+        {!this.props.isOpen ? null :
+            <div className="propertiesView-content">
+                {this.props.content}
+            </div>
+        }
+    </div>
+    }
+}
\ No newline at end of file
diff --git a/src/client/views/PropertiesView.scss b/src/client/views/PropertiesView.scss
index 897be9a32..889f5d5cf 100644
--- a/src/client/views/PropertiesView.scss
+++ b/src/client/views/PropertiesView.scss
@@ -6,122 +6,31 @@
     font-family: 'Roboto';
     font-size: 12px;
     cursor: auto;
+    border-left: $standard-border;
 
     .slider-text {
         font-size: 8px;
     }
 
-    overflow-x: hidden;
-    overflow-y: auto;
-
     .propertiesView-title {
-        text-align: center;
-        padding-top: 12px;
-        padding-bottom: 12px;
-        display: flex;
-        font-size: 18px;
+        padding: 10px;
+        font-size: 24px;
         font-weight: bold;
-        justify-content: center;
-
-        .propertiesView-title-icon {
-            width: 20px;
-            height: 20px;
-            padding-left: 38px;
-            margin-top: -5px;
-            align-items: flex-end;
-            margin-left: auto;
-            margin-right: 10px;
-
-            &:hover {
-                color: grey;
-                cursor: pointer;
-            }
-        }
     }
 
-    .propertiesView-name {
-        border-bottom: 1px solid black;
-        padding: 8.5px;
-        font-size: 12.5px;
+    overflow-x: hidden;
+    overflow-y: auto;
 
-        &:hover {
-            cursor: text;
-        }
+    .propertiesView-name,
+    .propertiesView-type {
+        padding: 0px 10px;
     }
 
-    .propertiesView-settings {
-        //border-bottom: 1px solid black;
-        //padding: 8.5px;
-        font-size: 12.5px;
-        font-weight: bold;
-
-        .propertiesView-settings-title {
-            font-weight: bold;
-            font-size: 12.5px;
-            padding: 4px;
-            display: flex;
-            color: white;
-            padding-left: 8px;
-            background-color: rgb(51, 51, 51);
-
-            &:hover {
-                cursor: pointer;
-            }
-
-            .propertiesView-settings-title-icon {
-                float: right;
-                justify-items: right;
-                align-items: flex-end;
-                margin-left: auto;
-                margin-right: 9px;
-
-                &:hover {
-                    cursor: pointer;
-                }
-            }
-        }
-
-        .propertiesView-settings-content {
-            margin-left: 12px;
-            padding-bottom: 10px;
-            padding-top: 8px;
-        }
-    }
 
     .propertiesView-sharing {
         //border-bottom: 1px solid black;
         //padding: 8.5px;
 
-        .propertiesView-sharing-title {
-            font-weight: bold;
-            font-size: 12.5px;
-            padding: 4px;
-            display: flex;
-            color: white;
-            padding-left: 8px;
-            background-color: rgb(51, 51, 51);
-
-            &:hover {
-                cursor: pointer;
-            }
-
-            .propertiesView-sharing-title-icon {
-                float: right;
-                justify-items: right;
-                align-items: flex-end;
-                margin-left: auto;
-                margin-right: 9px;
-
-                &:hover {
-                    cursor: pointer;
-                }
-            }
-        }
-
-        .propertiesView-sharing-content {
-            font-size: 10px;
-            padding: 10px;
-            margin-left: 5px;
 
             .propertiesView-buttonContainer {
                 float: right;
@@ -157,40 +66,13 @@
                     width: 100%;
                 }
             }
-        }
     }
 
     .propertiesView-filters {
         //border-bottom: 1px solid black;
         //padding: 8.5px;
 
-        .propertiesView-filters-title {
-            font-weight: bold;
-            font-size: 12.5px;
-            padding: 4px;
-            display: flex;
-            color: white;
-            padding-left: 8px;
-            background-color: rgb(51, 51, 51);
-
-            &:hover {
-                cursor: pointer;
-            }
-
-            .propertiesView-filters-title-icon {
-                float: right;
-                justify-items: right;
-                align-items: flex-end;
-                margin-left: auto;
-                margin-right: 9px;
-
-                &:hover {
-                    cursor: pointer;
-                }
-            }
-        }
-
-        .propertiesView-filters-content {
+        .propertiesView-content {
             font-size: 10px;
             padding: 10px;
             margin-left: 5px;
@@ -219,85 +101,10 @@
         }
     }
 
-    .propertiesView-appearance {
-        //border-bottom: 1px solid black;
-        //padding: 8.5px;
-
-        .propertiesView-appearance-title {
-            font-weight: bold;
-            font-size: 12.5px;
-            padding: 4px;
-            display: flex;
-            color: white;
-            padding-left: 8px;
-            background-color: rgb(51, 51, 51);
-
-            &:hover {
-                cursor: pointer;
-            }
-
-            .propertiesView-appearance-title-icon {
-                float: right;
-                justify-items: right;
-                align-items: flex-end;
-                margin-left: auto;
-                margin-right: 9px;
-
-                &:hover {
-                    cursor: pointer;
-                }
-            }
-        }
-
-        .propertiesView-appearance-content {
-            font-size: 10px;
-            padding: 10px;
-            margin-left: 5px;
-        }
-    }
-
-    .propertiesView-transform {
-        //border-bottom: 1px solid black;
-        //padding: 8.5px;
-
-        .propertiesView-transform-title {
-            font-weight: bold;
-            font-size: 12.5px;
-            padding: 4px;
-            display: flex;
-            color: white;
-            padding-left: 8px;
-            background-color: rgb(51, 51, 51);
-
-            &:hover {
-                cursor: pointer;
-            }
-
-            .propertiesView-transform-title-icon {
-                float: right;
-                justify-items: right;
-                align-items: flex-end;
-                margin-left: auto;
-                margin-right: 9px;
-
-                &:hover {
-                    cursor: pointer;
-                }
-            }
-        }
-
-        .propertiesView-transform-content {
-            font-size: 10px;
-            padding: 10px;
-            margin-left: 5px;
-        }
-    }
-
     .notify-button {
         padding: 2px;
         width: 12px;
         height: 12px;
-        background-color: black;
         border-radius: 10px;
         padding-left: 2px;
         padding-right: 2px;
@@ -393,58 +200,6 @@
         }
     }
 
-    .propertiesView-fields {
-        //border-bottom: 1px solid black;
-        //padding: 8.5px;
-
-        .propertiesView-fields-title {
-            font-weight: bold;
-            font-size: 12.5px;
-            padding: 4px;
-            display: flex;
-            color: white;
-            padding-left: 8px;
-            background-color: rgb(51, 51, 51);
-
-            &:hover {
-                cursor: pointer;
-            }
-
-            .propertiesView-fields-title-icon {
-                float: right;
-                justify-items: right;
-                align-items: flex-end;
-                margin-left: auto;
-                margin-right: 9px;
-
-                &:hover {
-                    cursor: pointer;
-                }
-            }
-        }
-
-        .propertiesView-fields-checkbox {
-            float: right;
-            height: 20px;
-            margin-top: -9px;
-
-            .propertiesView-fields-checkbox-text {
-                font-size: 7px;
-                margin-top: -10px;
-                margin-left: 6px;
-            }
-        }
-
-        .propertiesView-fields-content {
-            font-size: 10px;
-            margin-left: 2px;
-            padding: 10px;
-
-            &:hover {
-                cursor: pointer;
-            }
-        }
-    }
 
     .propertiesView-field {
         display: flex;
@@ -466,109 +221,14 @@
         }
     }
 
-    .propertiesView-contexts {
-        .propertiesView-contexts-title {
-            font-weight: bold;
-            font-size: 12.5px;
-            padding: 4px;
-            display: flex;
-            color: white;
-            padding-left: 8px;
-            background-color: rgb(51, 51, 51);
-
-            &:hover {
-                cursor: pointer;
-            }
-
-            .propertiesView-contexts-title-icon {
-                float: right;
-                justify-items: right;
-                align-items: flex-end;
-                margin-left: auto;
-                margin-right: 9px;
-
-                &:hover {
-                    cursor: pointer;
-                }
-            }
-        }
-
-        .propertiesView-contexts-content {
-            overflow: hidden;
-            padding: 10px;
-        }
-    }
-
-    .propertiesView-layout {
-        .propertiesView-layout-title {
-            font-weight: bold;
-            font-size: 12.5px;
-            padding: 4px;
-            display: flex;
-            color: white;
-            padding-left: 8px;
-            background-color: rgb(51, 51, 51);
-
-            &:hover {
-                cursor: pointer;
-            }
-
-            .propertiesView-layout-title-icon {
-                float: right;
-                justify-items: right;
-                align-items: flex-end;
-                margin-left: auto;
-                margin-right: 9px;
-
-                &:hover {
-                    cursor: pointer;
-                }
-            }
-        }
-
-        .propertiesView-layout-content {
-            overflow: hidden;
-            padding: 10px;
-        }
     }
 
     .propertiesView-presTrails {
         //border-bottom: 1px solid black;
         //padding: 8.5px;
 
-        .propertiesView-presTrails-title {
-            font-weight: bold;
-            font-size: 12.5px;
-            padding: 4px;
-            display: flex;
-            color: white;
-            padding-left: 8px;
-            background-color: rgb(51, 51, 51);
-
-            &:hover {
-                cursor: pointer;
-            }
-
-            .propertiesView-presTrails-title-icon {
-                float: right;
-                justify-items: right;
-                align-items: flex-end;
-                margin-left: auto;
-                margin-right: 9px;
-
-                &:hover {
-                    cursor: pointer;
-                }
-            }
-        }
-
-        .propertiesView-presTrails-content {
-            font-size: 10px;
-            padding: 10px;
-            margin-left: 5px;
-        }
+      
     }
-}
 
 .inking-button {
     display: flex;
@@ -847,10 +507,6 @@
     padding: 5%;
 }
 
-.propertiesView-section {
-    padding-left: 20px;
-}
-
 .propertiesView-input {
     padding: 4px 8px;
 
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 09aac053a..e86506f92 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -35,6 +35,8 @@ import { PropertiesDocBacklinksSelector } from './PropertiesDocBacklinksSelector
 import { PropertiesDocContextSelector } from './PropertiesDocContextSelector';
 import './PropertiesView.scss';
 import { DefaultStyleProvider } from './StyleProvider';
+import { Button, EditableText, NumberDropdown, Size, Slider, Type } from 'browndash-components';
+import { PropertiesSection } from './PropertiesSection';
 const higflyout = require('@hig/flyout');
 export const { anchorPoints } = higflyout;
 export const Flyout = higflyout.default;
@@ -332,7 +334,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         return (
             <Tooltip title={<div className="dash-tooltip">Notify with message</div>}>
                 <div className="notify-button">
-                    <FontAwesomeIcon className="notify-button-icon" icon="bell" color="white" size="sm" />
+                    <FontAwesomeIcon className="notify-button-icon" icon="bell"  size="sm" />
                 </div>
             </Tooltip>
         );
@@ -435,29 +437,57 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     @action
     toggleCheckbox = () => (this.layoutFields = !this.layoutFields);
 
+    @computed get color() {
+        return StrCast(Doc.UserDoc().userColor);
+    }
+
+    @computed get backgroundColor() {
+        return StrCast(Doc.UserDoc().userBackgroundColor);
+    }
+
+    @computed get variantColor() {
+        return StrCast(Doc.UserDoc().userVariantColor);
+    }
+
     @computed get editableTitle() {
         const titles = new Set<string>();
-        SelectionManager.Views().forEach(dv => titles.add(StrCast(dv.rootDoc.title)));
         const title = Array.from(titles.keys()).length > 1 ? '--multiple selected--' : StrCast(this.selectedDoc?.title);
+        SelectionManager.Views().forEach(dv => titles.add(StrCast(dv.rootDoc.title)));
         return (
-            <div className="editable-title">
-                <EditableView key="editableView" contents={title} height={25} fontSize={14} GetValue={() => title} SetValue={this.setTitle} />
-            </div>
+            <EditableText
+                val={title}
+                setVal={this.setTitle}
+                color={this.color}
+                type={Type.SEC}
+                formLabel={"Title"}
+                fillWidth
+            />
+        );
+    }
+
+    @computed get type() {
+        const type = StrCast(this.selectedDoc?.type);
+        return (
+            <Button
+                formLabel={"Type"}
+                text={type}
+                color={this.color}
+                align='flex-start'
+                fillWidth
+            />
         );
     }
 
     @undoBatch
     @action
-    setTitle = (value: string) => {
+    setTitle = (value: string | number) => {
+        console.log(value)
         if (SelectionManager.Views().length > 1) {
             SelectionManager.Views().map(dv => Doc.SetInPlace(dv.rootDoc, 'title', value, true));
-            return true;
         } else if (this.dataDoc) {
             if (this.selectedDoc) Doc.SetInPlace(this.selectedDoc, 'title', value, true);
-            else KeyValueBox.SetField(this.dataDoc, 'title', value, true);
-            return true;
+            else KeyValueBox.SetField(this.dataDoc, 'title', value as string, true);
         }
-        return false;
     };
 
     @undoBatch
@@ -515,7 +545,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                         className="inking-button-points"
                         style={{ backgroundColor: InkStrokeProperties.Instance._controlButton ? 'black' : '' }}
                         onPointerDown={action(() => (InkStrokeProperties.Instance._controlButton = !InkStrokeProperties.Instance._controlButton))}>
-                        <FontAwesomeIcon icon="bezier-curve" color="white" size="lg" />
+                        <FontAwesomeIcon icon="bezier-curve"  size="lg" />
                     </div>
                 </Tooltip>
             </div>
@@ -534,10 +564,10 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                 <input className="inputBox-input" type="text" value={value} onChange={e => setter(e.target.value)} onKeyPress={e => e.stopPropagation()} />
                 <div className="inputBox-button">
                     <div className="inputBox-button-up" key="up2" onPointerDown={undoBatch(action(() => this.upDownButtons('up', key)))}>
-                        <FontAwesomeIcon icon="caret-up" color="white" size="sm" />
+                        <FontAwesomeIcon icon="caret-up"  size="sm" />
                     </div>
                     <div className="inputbox-Button-down" key="down2" onPointerDown={undoBatch(action(() => this.upDownButtons('down', key)))}>
-                        <FontAwesomeIcon icon="caret-down" color="white" size="sm" />
+                        <FontAwesomeIcon icon="caret-down"  size="sm" />
                     </div>
                 </div>
             </div>
@@ -791,10 +821,10 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                 <input className="inputBox-input" type="text" value={value} onChange={e => setter(e.target.value)} />
                 <div className="inputBox-button">
                     <div className="inputBox-button-up" key="up2" onPointerDown={undoBatch(action(() => this.upDownButtons('up', key)))}>
-                        <FontAwesomeIcon icon="caret-up" color="white" size="sm" />
+                        <FontAwesomeIcon icon="caret-up"  size="sm" />
                     </div>
                     <div className="inputbox-Button-down" key="down2" onPointerDown={undoBatch(action(() => this.upDownButtons('down', key)))}>
-                        <FontAwesomeIcon icon="caret-down" color="white" size="sm" />
+                        <FontAwesomeIcon icon="caret-down"  size="sm" />
                     </div>
                 </div>
             </div>
@@ -884,6 +914,29 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         return (
             <div className="transform-editor">
                 {this.isInk ? this.controlPointsButton : null}
+                <Slider 
+                    formLabel={'Height'} 
+                    multithumb={false}
+                    color={this.color}
+                    size={Size.XSMALL} 
+                    min={0} 
+                    max={1000} 
+                    number={Number(this.shapeHgt)}
+                    setNumber={undoable((val: string) => !isNaN(Number(val)) && (this.shapeHgt = val), 'set height')}
+                    fillWidth
+                />
+                <Slider 
+                    formLabel={'Width'} 
+                    multithumb={false}
+                    color={this.color}
+                    size={Size.XSMALL} 
+                    min={0} 
+                    max={1000} 
+                    number={Number(this.shapeWid)}
+                    setNumber={undoable((val: string) => !isNaN(Number(val)) && (this.shapeWid = val), 'set width')}
+                    fillWidth
+                />
+
                 {this.hgtInput}
                 {this.XpsInput}
             </div>
@@ -891,52 +944,38 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     }
 
     @computed get optionsSubMenu() {
-        return (
-            <div className="propertiesView-settings" onPointerEnter={action(() => (this.inOptions = true))} onPointerLeave={action(() => (this.inOptions = false))}>
-                <div className="propertiesView-settings-title" onPointerDown={action(() => (this.openOptions = !this.openOptions))} style={{ backgroundColor: this.openOptions ? 'black' : '' }}>
-                    Options
-                    <div className="propertiesView-settings-title-icon">
-                        <FontAwesomeIcon icon={this.openOptions ? 'caret-down' : 'caret-right'} size="lg" color="white" />
-                    </div>
-                </div>
-                {!this.openOptions ? null : (
-                    <div className="propertiesView-settings-content">
-                        <PropertiesButtons />
-                    </div>
-                )}
-            </div>
-        );
+        return <PropertiesSection
+            title="Options"
+            content={<PropertiesButtons />}
+            inSection={this.inOptions}
+            isOpen={this.openOptions}
+            setInSection={(bool) => this.inOptions = bool}
+            setIsOpen={(bool) => this.openOptions = bool}
+        />
     }
 
     @computed get sharingSubMenu() {
-        return (
-            <div className="propertiesView-sharing">
-                <div className="propertiesView-sharing-title" onPointerDown={action(() => (this.openSharing = !this.openSharing))} style={{ backgroundColor: this.openSharing ? 'black' : '' }}>
-                    Sharing {'&'} Permissions
-                    <div className="propertiesView-sharing-title-icon">
-                        <FontAwesomeIcon icon={this.openSharing ? 'caret-down' : 'caret-right'} size="lg" color="white" />
-                    </div>
-                </div>
-                {!this.openSharing ? null : (
-                    <div className="propertiesView-sharing-content">
-                        <div className="propertiesView-buttonContainer">
-                            {!Doc.noviceMode ? (
-                                <div className="propertiesView-acls-checkbox">
-                                    <Checkbox color="primary" onChange={action(() => (this.layoutDocAcls = !this.layoutDocAcls))} checked={this.layoutDocAcls} />
-                                    <div className="propertiesView-acls-checkbox-text">Layout</div>
-                                </div>
-                            ) : null}
-                            {/* <Tooltip title={<><div className="dash-tooltip">{"Re-distribute sharing settings"}</div></>}>
-                                        <button onPointerDown={() => SharingManager.Instance.distributeOverCollection(this.selectedDoc!)}>
-                                            <FontAwesomeIcon icon="redo-alt" color="white" size="1x" />
-                                        </button>
-                                    </Tooltip> */}
+        return <PropertiesSection
+            title="Sharing & Permissions"
+            content={<>
+            <div className="propertiesView-buttonContainer">
+                {!Doc.noviceMode ? (
+                        <div className="propertiesView-acls-checkbox">
+                            <Checkbox color="primary" onChange={action(() => (this.layoutDocAcls = !this.layoutDocAcls))} checked={this.layoutDocAcls} />
+                            <div className="propertiesView-acls-checkbox-text">Layout</div>
                         </div>
-                        {this.sharingTable}
-                    </div>
-                )}
-            </div>
-        );
+                    ) : null}
+                    {/* <Tooltip title={<><div className="dash-tooltip">{"Re-distribute sharing settings"}</div></>}>
+                        <button onPointerDown={() => SharingManager.Instance.distributeOverCollection(this.selectedDoc!)}>
+                            <FontAwesomeIcon icon="redo-alt"  size="1x" />
+                        </button>
+                    </Tooltip> */}
+                </div>
+                {this.sharingTable}
+            </>}
+            isOpen={this.openSharing}
+            setIsOpen={(bool) => this.openSharing = bool}
+        />
     }
 
     /**
@@ -964,111 +1003,71 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     };
 
     @computed get filtersSubMenu() {
-        return (
-            <div className="propertiesView-filters">
-                <div className="propertiesView-filters-title" onPointerDown={action(() => (this.openFilters = !this.openFilters))} style={{ backgroundColor: this.openFilters ? 'black' : '' }}>
-                    Filters
-                    <div className="propertiesView-filters-title-icon">
-                        <FontAwesomeIcon icon={this.openFilters ? 'caret-down' : 'caret-right'} size="lg" color="white" />
-                    </div>
-                </div>
-                {!this.openFilters ? null : (
-                    <div className="propertiesView-filters-content" style={{ position: 'relative', height: 'auto' }}>
-                        <FilterPanel rootDoc={this.selectedDoc ?? Doc.ActiveDashboard!} />
-                    </div>
-                )}
-            </div>
-        );
+        return <PropertiesSection 
+            title="Filters"
+            content={<div className="propertiesView-content filters" style={{ position: 'relative', height: 'auto' }}>
+                <FilterPanel rootDoc={this.selectedDoc ?? Doc.ActiveDashboard!} />
+            </div>}
+            isOpen={this.openFilters}
+            setIsOpen={(bool) => this.openFilters = bool}
+        />
     }
 
     @computed get inkSubMenu() {
         return (
             <>
-                {!this.isInk ? null : (
-                    <div className="propertiesView-appearance">
-                        <div className="propertiesView-appearance-title" onPointerDown={action(() => (this.openAppearance = !this.openAppearance))} style={{ backgroundColor: this.openAppearance ? 'black' : '' }}>
-                            Appearance
-                            <div className="propertiesView-appearance-title-icon">
-                                <FontAwesomeIcon icon={this.openAppearance ? 'caret-down' : 'caret-right'} size="lg" color="white" />
-                            </div>
-                        </div>
-                        {!this.openAppearance ? null : <div className="propertiesView-appearance-content">{this.appearanceEditor}</div>}
-                    </div>
-                )}
-
-                <div className="propertiesView-transform">
-                    <div className="propertiesView-transform-title" onPointerDown={action(() => (this.openTransform = !this.openTransform))} style={{ backgroundColor: this.openTransform ? 'black' : '' }}>
-                        Transform
-                        <div className="propertiesView-transform-title-icon">
-                            <FontAwesomeIcon icon={this.openTransform ? 'caret-down' : 'caret-right'} size="lg" color="white" />
-                        </div>
-                    </div>
-                    {this.openTransform ? <div className="propertiesView-transform-content">{this.transformEditor}</div> : null}
-                </div>
+                <PropertiesSection
+                    title="Appearance"
+                    content={this.isInk ? this.appearanceEditor : null}
+                    isOpen={this.openAppearance}
+                    setIsOpen={(bool) => this.openAppearance = bool}
+                />
+                <PropertiesSection
+                    title="Transform"
+                    content={this.transformEditor}
+                    isOpen={this.openTransform}
+                    setIsOpen={(bool) => this.openTransform = bool}
+                />
             </>
         );
     }
 
     @computed get fieldsSubMenu() {
-        return (
-            <div className="propertiesView-fields">
-                <div className="propertiesView-fields-title" onPointerDown={action(() => (this.openFields = !this.openFields))} style={{ backgroundColor: this.openFields ? 'black' : '' }}>
-                    Fields {'&'} Tags
-                    <div className="propertiesView-fields-title-icon">
-                        <FontAwesomeIcon icon={this.openFields ? 'caret-down' : 'caret-right'} size="lg" color="white" />
-                    </div>
-                </div>
-                {!Doc.noviceMode && this.openFields ? (
-                    <div className="propertiesView-fields-checkbox">
-                        {this.fieldsCheckbox}
-                        <div className="propertiesView-fields-checkbox-text">Layout</div>
-                    </div>
-                ) : null}
-                {!this.openFields ? null : <div className="propertiesView-fields-content">{Doc.noviceMode ? this.noviceFields : this.expandedField}</div>}
-            </div>
-        );
+        return <PropertiesSection
+            title="Fields & Tags"
+            content={<div className="propertiesView-content fields">{
+                Doc.noviceMode ? this.noviceFields : this.expandedField}
+            </div>}
+            isOpen={this.openFields}
+            setIsOpen={(bool) => this.openFields = bool}
+        />
     }
 
     @computed get contextsSubMenu() {
-        return (
-            <div className="propertiesView-contexts">
-                <div className="propertiesView-contexts-title" onPointerDown={action(() => (this.openContexts = !this.openContexts))} style={{ backgroundColor: this.openContexts ? 'black' : '' }}>
-                    Other Contexts
-                    <div className="propertiesView-contexts-title-icon">
-                        <FontAwesomeIcon icon={this.openContexts ? 'caret-down' : 'caret-right'} size="lg" color="white" />
-                    </div>
-                </div>
-                {this.openContexts ? <div className="propertiesView-contexts-content">{this.contexts}</div> : null}
-            </div>
-        );
+        return <PropertiesSection
+            title="Other Contexts"
+            content={this.contexts}
+            isOpen={this.openContexts}
+            setIsOpen={(bool) => this.openContexts = bool}
+        />
     }
 
     @computed get linksSubMenu() {
-        return (
-            <div className="propertiesView-contexts">
-                <div className="propertiesView-contexts-title" onPointerDown={action(() => (this.openLinks = !this.openLinks))} style={{ backgroundColor: this.openLinks ? 'black' : '' }}>
-                    Linked To
-                    <div className="propertiesView-contexts-title-icon">
-                        <FontAwesomeIcon icon={this.openLinks ? 'caret-down' : 'caret-right'} size="lg" color="white" />
-                    </div>
-                </div>
-                {this.openLinks ? <div className="propertiesView-contexts-content">{this.links}</div> : null}
-            </div>
-        );
+        return <PropertiesSection
+            title="Linked To"
+            content={this.links}
+            isOpen={this.openLinks}
+            setIsOpen={(bool) => this.openLinks = bool}
+        />
     }
 
     @computed get layoutSubMenu() {
-        return (
-            <div className="propertiesView-layout">
-                <div className="propertiesView-layout-title" onPointerDown={action(() => (this.openLayout = !this.openLayout))} style={{ backgroundColor: this.openLayout ? 'black' : '' }}>
-                    Layout
-                    <div className="propertiesView-layout-title-icon">
-                        <FontAwesomeIcon icon={this.openLayout ? 'caret-down' : 'caret-right'} size="lg" color="white" />
-                    </div>
-                </div>
-                {this.openLayout ? <div className="propertiesView-layout-content">{this.layoutPreview}</div> : null}
-            </div>
-        );
+        return <PropertiesSection
+            title="Layout"
+            content={this.layoutPreview}
+            isOpen={this.openLayout}
+            setIsOpen={(bool) => this.openLayout = bool}
+        />
     }
 
     @computed get description() {
@@ -1269,6 +1268,226 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         if (scale > 1) scale = 1;
         this.sourceAnchor && (this.sourceAnchor.followLinkZoomScale = scale);
     };
+    
+    @computed get linkProperties() {
+        const zoom = Number((NumCast(this.sourceAnchor?.followLinkZoomScale, 1) * 100).toPrecision(3));
+        const targZoom = this.sourceAnchor?.followLinkZoom;
+        const indent = 30;
+        const hasSelectedAnchor = LinkManager.Links(this.sourceAnchor).includes(LinkManager.currentLink!);
+
+        return <>
+        <div className="propertiesView-section" style={{ background: 'darkgray' }}>
+            <div className="propertiesView-input first" style={{ display: 'grid', gridTemplateColumns: '84px auto' }}>
+                <p>Relationship</p>
+                {this.editRelationship}
+            </div>
+            <div className="propertiesView-input" style={{ display: 'grid', gridTemplateColumns: '84px auto' }}>
+                <p>Description</p>
+                {this.editDescription}
+            </div>
+            <div className="propertiesView-input inline">
+                <p>Show link</p>
+                <button
+                    style={{ background: !LinkManager.currentLink?.link_displayLine ? '' : '#4476f7', borderRadius: 3 }}
+                    onPointerDown={e => this.toggleLinkProp(e, 'link_displayLine')}
+                    onClick={e => e.stopPropagation()}
+                    className="propertiesButton">
+                    <FontAwesomeIcon className="fa-icon" icon={faArrowRight as IconLookup} size="lg" />
+                </button>
+            </div>
+            <div className="propertiesView-input inline" style={{ marginLeft: 10 }}>
+                <p>Auto-move anchors</p>
+                <button
+                    style={{ background: !LinkManager.currentLink?.link_autoMoveAnchors ? '' : '#4476f7', borderRadius: 3 }}
+                    onPointerDown={e => this.toggleLinkProp(e, 'link_autoMoveAnchors')}
+                    onClick={e => e.stopPropagation()}
+                    className="propertiesButton">
+                    <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
+                </button>
+            </div>
+            <div className="propertiesView-input inline" style={{ marginLeft: 10 }}>
+                <p>Display arrow</p>
+                <button
+                    style={{ background: !LinkManager.currentLink?.link_displayArrow ? '' : '#4476f7', borderRadius: 3 }}
+                    onPointerDown={e => this.toggleLinkProp(e, 'link_displayArrow')}
+                    onClick={e => e.stopPropagation()}
+                    className="propertiesButton">
+                    <FontAwesomeIcon className="fa-icon" icon={faArrowRight as IconLookup} size="lg" />
+                </button>
+            </div>
+        </div>
+        {!hasSelectedAnchor ? null : (
+            <div className="propertiesView-section">
+                <div className="propertiesView-input inline first" style={{ display: 'grid', gridTemplateColumns: '84px calc(100% - 84px)' }}>
+                    <p>Follow by</p>
+                    <select onChange={e => this.changeFollowBehavior(e.currentTarget.value === 'Default' ? undefined : e.currentTarget.value)} value={Cast(this.sourceAnchor?.followLinkLocation, 'string', null)}>
+                        <option value={undefined}>Default</option>
+                        <option value={OpenWhere.addLeft}>Opening in new left pane</option>
+                        <option value={OpenWhere.addRight}>Opening in new right pane</option>
+                        <option value={OpenWhere.replaceLeft}>Replacing left tab</option>
+                        <option value={OpenWhere.replaceRight}>Replacing right tab</option>
+                        <option value={OpenWhere.fullScreen}>Overlaying current tab</option>
+                        <option value={OpenWhere.lightbox}>Opening in lightbox</option>
+                        <option value={OpenWhere.add}>Opening in new tab</option>
+                        <option value={OpenWhere.replace}>Replacing current tab</option>
+                        <option value={OpenWhere.inParent}>Opening in same collection</option>
+                        {LinkManager.currentLink?.linksToAnnotation ? <option value="openExternal">Open in external page</option> : null}
+                    </select>
+                </div>
+                <div className="propertiesView-input inline first" style={{ display: 'grid', gridTemplateColumns: '84px calc(100% - 134px) 50px' }}>
+                    <p>Animation</p>
+                    <select style={{ width: '100%', gridColumn: 2 }} onChange={e => this.changeAnimationBehavior(e.currentTarget.value)} value={StrCast(this.sourceAnchor?.followLinkAnimEffect, 'default')}>
+                        <option value="default">Default</option>
+                        {[PresEffect.None, PresEffect.Zoom, PresEffect.Lightspeed, PresEffect.Fade, PresEffect.Flip, PresEffect.Rotate, PresEffect.Bounce, PresEffect.Roll].map(effect => (
+                            <option key={effect.toString()} value={effect.toString()}>
+                                {effect.toString()}
+                            </option>
+                        ))}
+                    </select>
+                    <div className="effectDirection" style={{ marginLeft: '10px', display: 'grid', width: 40, height: 36, gridColumn: 3, gridTemplateRows: '12px 12px 12px' }}>
+                        {this.animationDirection(PresEffectDirection.Left, 'angle-right', 1, 2, {})}
+                        {this.animationDirection(PresEffectDirection.Right, 'angle-left', 3, 2, {})}
+                        {this.animationDirection(PresEffectDirection.Top, 'angle-down', 2, 1, {})}
+                        {this.animationDirection(PresEffectDirection.Bottom, 'angle-up', 2, 3, {})}
+                        {this.animationDirection(PresEffectDirection.Center, '', 2, 2, { width: 10, height: 10, alignSelf: 'center' })}
+                    </div>
+                </div>
+                {PresBox.inputter(
+                    '0.1',
+                    '0.1',
+                    '10',
+                    NumCast(this.sourceAnchor?.followLinkTransitionTime) / 1000,
+                    true,
+                    (val: string) => PresBox.SetTransitionTime(val, (timeInMS: number) => this.sourceAnchor && (this.sourceAnchor.followLinkTransitionTime = timeInMS)),
+                    indent
+                )}{' '}
+                <div
+                    className={'slider-headers'}
+                    style={{
+                        display: 'grid',
+                        justifyContent: 'space-between',
+                        width: `calc(100% - ${indent * 2}px)`,
+                        marginLeft: indent,
+                        marginRight: indent,
+                        gridTemplateColumns: 'auto auto',
+                        borderTop: 'solid',
+                    }}>
+                    <div className="slider-text">Fast</div>
+                    <div className="slider-text">Slow</div>
+                </div>{' '}
+                <div className="propertiesView-input inline">
+                    <p>Play Target Audio</p>
+                    <button
+                        style={{ background: !this.sourceAnchor?.followLinkAudio ? '' : '#4476f7', borderRadius: 3 }}
+                        onPointerDown={e => this.toggleAnchorProp(e, 'followLinkAudio', this.sourceAnchor)}
+                        onClick={e => e.stopPropagation()}
+                        className="propertiesButton">
+                        <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
+                    </button>
+                </div>
+                <div className="propertiesView-input inline">
+                    <p>Zoom Text Selections</p>
+                    <button
+                        style={{ background: !this.sourceAnchor?.followLinkZoomText ? '' : '#4476f7', borderRadius: 3 }}
+                        onPointerDown={e => this.toggleAnchorProp(e, 'followLinkZoomText', this.sourceAnchor)}
+                        onClick={e => e.stopPropagation()}
+                        className="propertiesButton">
+                        <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
+                    </button>
+                </div>
+                <div className="propertiesView-input inline">
+                    <p>Toggle Follow to Outer Context</p>
+                    <button
+                        style={{ background: !this.sourceAnchor?.followLinkToOuterContext ? '' : '#4476f7', borderRadius: 3 }}
+                        onPointerDown={e => this.toggleAnchorProp(e, 'followLinkToOuterContext', this.sourceAnchor)}
+                        onClick={e => e.stopPropagation()}
+                        className="propertiesButton">
+                        <FontAwesomeIcon className="fa-icon" icon={faWindowMaximize as IconLookup} size="lg" />
+                    </button>
+                </div>
+                <div className="propertiesView-input inline">
+                    <p>Toggle Target (Show/Hide)</p>
+                    <button
+                        style={{ background: !this.sourceAnchor?.followLinkToggle ? '' : '#4476f7', borderRadius: 3 }}
+                        onPointerDown={e => this.toggleAnchorProp(e, 'followLinkToggle', this.sourceAnchor)}
+                        onClick={e => e.stopPropagation()}
+                        className="propertiesButton">
+                        <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
+                    </button>
+                </div>
+                <div className="propertiesView-input inline">
+                    <p>Ease Transitions</p>
+                    <button
+                        style={{ background: this.sourceAnchor?.followLinkEase === 'linear' ? '' : '#4476f7', borderRadius: 3 }}
+                        onPointerDown={e => this.toggleAnchorProp(e, 'followLinkEase', this.sourceAnchor, 'ease', 'linear')}
+                        onClick={e => e.stopPropagation()}
+                        className="propertiesButton">
+                        <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
+                    </button>
+                </div>
+                <div className="propertiesView-input inline">
+                    <p>Capture Offset to Target</p>
+                    <button
+                        style={{ background: this.sourceAnchor?.followLinkXoffset === undefined ? '' : '#4476f7', borderRadius: 3 }}
+                        onPointerDown={e => {
+                            this.toggleAnchorProp(e, 'followLinkXoffset', this.sourceAnchor, NumCast(this.destinationAnchor?.x) - NumCast(this.sourceAnchor?.x), undefined);
+                            this.toggleAnchorProp(e, 'followLinkYoffset', this.sourceAnchor, NumCast(this.destinationAnchor?.y) - NumCast(this.sourceAnchor?.y), undefined);
+                        }}
+                        onClick={e => e.stopPropagation()}
+                        className="propertiesButton">
+                        <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
+                    </button>
+                </div>
+                <div className="propertiesView-input inline">
+                    <p>Center Target (no zoom)</p>
+                    <button
+                        style={{ background: this.sourceAnchor?.followLinkZoom ? '' : '#4476f7', borderRadius: 3 }}
+                        onPointerDown={e => this.toggleAnchorProp(e, 'followLinkZoom', this.sourceAnchor)}
+                        onClick={e => e.stopPropagation()}
+                        className="propertiesButton">
+                        <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
+                    </button>
+                </div>
+                <div className="propertiesView-input inline" style={{ display: 'grid', gridTemplateColumns: '78px calc(100% - 108px) 50px' }}>
+                    <p>Zoom %</p>
+                    <div className="ribbon-property" style={{ display: !targZoom ? 'none' : 'inline-flex' }}>
+                        <input className="presBox-input" style={{ width: '100%' }} readOnly={true} type="number" value={zoom} />
+                        <div className="ribbon-propertyUpDown" style={{ display: 'flex', flexDirection: 'column' }}>
+                            <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setZoom(String(zoom), 0.1))}>
+                                <FontAwesomeIcon icon={'caret-up'} />
+                            </div>
+                            <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setZoom(String(zoom), -0.1))}>
+                                <FontAwesomeIcon icon={'caret-down'} />
+                            </div>
+                        </div>
+                    </div>
+                    <button
+                        style={{ background: !targZoom || this.sourceAnchor?.followLinkZoomScale === 0 ? '' : '#4476f7', borderRadius: 3, gridColumn: 3 }}
+                        onPointerDown={e => this.toggleAnchorProp(e, 'followLinkZoom', this.sourceAnchor)}
+                        onClick={e => e.stopPropagation()}
+                        className="propertiesButton">
+                        <FontAwesomeIcon className="fa-icon" icon={faArrowRight as IconLookup} size="lg" />
+                    </button>
+                </div>
+                {!targZoom ? null : PresBox.inputter('0', '1', '100', zoom, true, this.setZoom, 30)}
+                <div
+                    className={'slider-headers'}
+                    style={{
+                        display: !targZoom ? 'none' : 'grid',
+                        justifyContent: 'space-between',
+                        width: `calc(100% - ${indent * 2}px)`,
+                        marginLeft: indent,
+                        marginRight: indent,
+                        gridTemplateColumns: 'auto auto',
+                        borderTop: 'solid',
+                    }}>
+                    <div className="slider-text">0%</div>
+                    <div className="slider-text">100%</div>
+                </div>{' '}
+            </div>
+        )}
+    </>
+    }
 
     /**
      * Handles adding and removing members from the sharing panel
@@ -1283,9 +1502,6 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
 
     render() {
         const isNovice = Doc.noviceMode;
-        const zoom = Number((NumCast(this.sourceAnchor?.followLinkZoomScale, 1) * 100).toPrecision(3));
-        const targZoom = this.sourceAnchor?.followLinkZoom;
-        const indent = 30;
         const hasSelectedAnchor = LinkManager.Links(this.sourceAnchor).includes(LinkManager.currentLink!);
         if (!this.selectedDoc && !this.isPres) {
             return (
@@ -1301,243 +1517,26 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                     <div
                         className="propertiesView"
                         style={{
+                            background: StrCast(Doc.UserDoc().userBackgroundColor),
+                            color: StrCast(Doc.UserDoc().userColor),
                             width: this.props.width,
                             minWidth: this.props.width,
-                            //overflowY: this.scrolling ? "scroll" : "visible"
                         }}>
                         <div className="propertiesView-title" style={{ width: this.props.width }}>
                             Properties
                         </div>
                         <div className="propertiesView-name">{this.editableTitle}</div>
-
+                        <div className="propertiesView-type">{this.type}</div>
                         {this.contextsSubMenu}
-
                         {this.linksSubMenu}
                         {!this.selectedDoc || !LinkManager.currentLink || (!hasSelectedAnchor && this.selectedDoc !== LinkManager.currentLink) ? null : (
-                            <>
-                                <div className="propertiesView-section" style={{ background: 'darkgray' }}>
-                                    <div className="propertiesView-input first" style={{ display: 'grid', gridTemplateColumns: '84px auto' }}>
-                                        <p>Relationship</p>
-                                        {this.editRelationship}
-                                    </div>
-                                    <div className="propertiesView-input" style={{ display: 'grid', gridTemplateColumns: '84px auto' }}>
-                                        <p>Description</p>
-                                        {this.editDescription}
-                                    </div>
-                                    <div className="propertiesView-input inline">
-                                        <p>Show link</p>
-                                        <button
-                                            style={{ background: !LinkManager.currentLink?.link_displayLine ? '' : '#4476f7', borderRadius: 3 }}
-                                            onPointerDown={e => this.toggleLinkProp(e, 'link_displayLine')}
-                                            onClick={e => e.stopPropagation()}
-                                            className="propertiesButton">
-                                            <FontAwesomeIcon className="fa-icon" icon={faArrowRight as IconLookup} size="lg" />
-                                        </button>
-                                    </div>
-                                    <div className="propertiesView-input inline" style={{ marginLeft: 10 }}>
-                                        <p>Auto-move anchors</p>
-                                        <button
-                                            style={{ background: !LinkManager.currentLink?.link_autoMoveAnchors ? '' : '#4476f7', borderRadius: 3 }}
-                                            onPointerDown={e => this.toggleLinkProp(e, 'link_autoMoveAnchors')}
-                                            onClick={e => e.stopPropagation()}
-                                            className="propertiesButton">
-                                            <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
-                                        </button>
-                                    </div>
-                                    <div className="propertiesView-input inline" style={{ marginLeft: 10 }}>
-                                        <p>Display arrow</p>
-                                        <button
-                                            style={{ background: !LinkManager.currentLink?.link_displayArrow ? '' : '#4476f7', borderRadius: 3 }}
-                                            onPointerDown={e => this.toggleLinkProp(e, 'link_displayArrow')}
-                                            onClick={e => e.stopPropagation()}
-                                            className="propertiesButton">
-                                            <FontAwesomeIcon className="fa-icon" icon={faArrowRight as IconLookup} size="lg" />
-                                        </button>
-                                    </div>
-                                </div>
-                                {!hasSelectedAnchor ? null : (
-                                    <div className="propertiesView-section">
-                                        <div className="propertiesView-input inline first" style={{ display: 'grid', gridTemplateColumns: '84px calc(100% - 84px)' }}>
-                                            <p>Follow by</p>
-                                            <select onChange={e => this.changeFollowBehavior(e.currentTarget.value === 'Default' ? undefined : e.currentTarget.value)} value={Cast(this.sourceAnchor?.followLinkLocation, 'string', null)}>
-                                                <option value={undefined}>Default</option>
-                                                <option value={OpenWhere.addLeft}>Opening in new left pane</option>
-                                                <option value={OpenWhere.addRight}>Opening in new right pane</option>
-                                                <option value={OpenWhere.replaceLeft}>Replacing left tab</option>
-                                                <option value={OpenWhere.replaceRight}>Replacing right tab</option>
-                                                <option value={OpenWhere.fullScreen}>Overlaying current tab</option>
-                                                <option value={OpenWhere.lightbox}>Opening in lightbox</option>
-                                                <option value={OpenWhere.add}>Opening in new tab</option>
-                                                <option value={OpenWhere.replace}>Replacing current tab</option>
-                                                <option value={OpenWhere.inParent}>Opening in same collection</option>
-                                                {LinkManager.currentLink?.linksToAnnotation ? <option value="openExternal">Open in external page</option> : null}
-                                            </select>
-                                        </div>
-                                        <div className="propertiesView-input inline first" style={{ display: 'grid', gridTemplateColumns: '84px calc(100% - 134px) 50px' }}>
-                                            <p>Animation</p>
-                                            <select style={{ width: '100%', gridColumn: 2 }} onChange={e => this.changeAnimationBehavior(e.currentTarget.value)} value={StrCast(this.sourceAnchor?.followLinkAnimEffect, 'default')}>
-                                                <option value="default">Default</option>
-                                                {[PresEffect.None, PresEffect.Zoom, PresEffect.Lightspeed, PresEffect.Fade, PresEffect.Flip, PresEffect.Rotate, PresEffect.Bounce, PresEffect.Roll].map(effect => (
-                                                    <option key={effect.toString()} value={effect.toString()}>
-                                                        {effect.toString()}
-                                                    </option>
-                                                ))}
-                                            </select>
-                                            <div className="effectDirection" style={{ marginLeft: '10px', display: 'grid', width: 40, height: 36, gridColumn: 3, gridTemplateRows: '12px 12px 12px' }}>
-                                                {this.animationDirection(PresEffectDirection.Left, 'angle-right', 1, 2, {})}
-                                                {this.animationDirection(PresEffectDirection.Right, 'angle-left', 3, 2, {})}
-                                                {this.animationDirection(PresEffectDirection.Top, 'angle-down', 2, 1, {})}
-                                                {this.animationDirection(PresEffectDirection.Bottom, 'angle-up', 2, 3, {})}
-                                                {this.animationDirection(PresEffectDirection.Center, '', 2, 2, { width: 10, height: 10, alignSelf: 'center' })}
-                                            </div>
-                                        </div>
-                                        {PresBox.inputter(
-                                            '0.1',
-                                            '0.1',
-                                            '10',
-                                            NumCast(this.sourceAnchor?.followLinkTransitionTime) / 1000,
-                                            true,
-                                            (val: string) => PresBox.SetTransitionTime(val, (timeInMS: number) => this.sourceAnchor && (this.sourceAnchor.followLinkTransitionTime = timeInMS)),
-                                            indent
-                                        )}{' '}
-                                        <div
-                                            className={'slider-headers'}
-                                            style={{
-                                                display: 'grid',
-                                                justifyContent: 'space-between',
-                                                width: `calc(100% - ${indent * 2}px)`,
-                                                marginLeft: indent,
-                                                marginRight: indent,
-                                                gridTemplateColumns: 'auto auto',
-                                                borderTop: 'solid',
-                                            }}>
-                                            <div className="slider-text">Fast</div>
-                                            <div className="slider-text">Slow</div>
-                                        </div>{' '}
-                                        <div className="propertiesView-input inline">
-                                            <p>Play Target Audio</p>
-                                            <button
-                                                style={{ background: !this.sourceAnchor?.followLinkAudio ? '' : '#4476f7', borderRadius: 3 }}
-                                                onPointerDown={e => this.toggleAnchorProp(e, 'followLinkAudio', this.sourceAnchor)}
-                                                onClick={e => e.stopPropagation()}
-                                                className="propertiesButton">
-                                                <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
-                                            </button>
-                                        </div>
-                                        <div className="propertiesView-input inline">
-                                            <p>Zoom Text Selections</p>
-                                            <button
-                                                style={{ background: !this.sourceAnchor?.followLinkZoomText ? '' : '#4476f7', borderRadius: 3 }}
-                                                onPointerDown={e => this.toggleAnchorProp(e, 'followLinkZoomText', this.sourceAnchor)}
-                                                onClick={e => e.stopPropagation()}
-                                                className="propertiesButton">
-                                                <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
-                                            </button>
-                                        </div>
-                                        <div className="propertiesView-input inline">
-                                            <p>Toggle Follow to Outer Context</p>
-                                            <button
-                                                style={{ background: !this.sourceAnchor?.followLinkToOuterContext ? '' : '#4476f7', borderRadius: 3 }}
-                                                onPointerDown={e => this.toggleAnchorProp(e, 'followLinkToOuterContext', this.sourceAnchor)}
-                                                onClick={e => e.stopPropagation()}
-                                                className="propertiesButton">
-                                                <FontAwesomeIcon className="fa-icon" icon={faWindowMaximize as IconLookup} size="lg" />
-                                            </button>
-                                        </div>
-                                        <div className="propertiesView-input inline">
-                                            <p>Toggle Target (Show/Hide)</p>
-                                            <button
-                                                style={{ background: !this.sourceAnchor?.followLinkToggle ? '' : '#4476f7', borderRadius: 3 }}
-                                                onPointerDown={e => this.toggleAnchorProp(e, 'followLinkToggle', this.sourceAnchor)}
-                                                onClick={e => e.stopPropagation()}
-                                                className="propertiesButton">
-                                                <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
-                                            </button>
-                                        </div>
-                                        <div className="propertiesView-input inline">
-                                            <p>Ease Transitions</p>
-                                            <button
-                                                style={{ background: this.sourceAnchor?.followLinkEase === 'linear' ? '' : '#4476f7', borderRadius: 3 }}
-                                                onPointerDown={e => this.toggleAnchorProp(e, 'followLinkEase', this.sourceAnchor, 'ease', 'linear')}
-                                                onClick={e => e.stopPropagation()}
-                                                className="propertiesButton">
-                                                <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
-                                            </button>
-                                        </div>
-                                        <div className="propertiesView-input inline">
-                                            <p>Capture Offset to Target</p>
-                                            <button
-                                                style={{ background: this.sourceAnchor?.followLinkXoffset === undefined ? '' : '#4476f7', borderRadius: 3 }}
-                                                onPointerDown={e => {
-                                                    this.toggleAnchorProp(e, 'followLinkXoffset', this.sourceAnchor, NumCast(this.destinationAnchor?.x) - NumCast(this.sourceAnchor?.x), undefined);
-                                                    this.toggleAnchorProp(e, 'followLinkYoffset', this.sourceAnchor, NumCast(this.destinationAnchor?.y) - NumCast(this.sourceAnchor?.y), undefined);
-                                                }}
-                                                onClick={e => e.stopPropagation()}
-                                                className="propertiesButton">
-                                                <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
-                                            </button>
-                                        </div>
-                                        <div className="propertiesView-input inline">
-                                            <p>Center Target (no zoom)</p>
-                                            <button
-                                                style={{ background: this.sourceAnchor?.followLinkZoom ? '' : '#4476f7', borderRadius: 3 }}
-                                                onPointerDown={e => this.toggleAnchorProp(e, 'followLinkZoom', this.sourceAnchor)}
-                                                onClick={e => e.stopPropagation()}
-                                                className="propertiesButton">
-                                                <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
-                                            </button>
-                                        </div>
-                                        <div className="propertiesView-input inline" style={{ display: 'grid', gridTemplateColumns: '78px calc(100% - 108px) 50px' }}>
-                                            <p>Zoom %</p>
-                                            <div className="ribbon-property" style={{ display: !targZoom ? 'none' : 'inline-flex' }}>
-                                                <input className="presBox-input" style={{ width: '100%' }} readOnly={true} type="number" value={zoom} />
-                                                <div className="ribbon-propertyUpDown" style={{ display: 'flex', flexDirection: 'column' }}>
-                                                    <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setZoom(String(zoom), 0.1))}>
-                                                        <FontAwesomeIcon icon={'caret-up'} />
-                                                    </div>
-                                                    <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setZoom(String(zoom), -0.1))}>
-                                                        <FontAwesomeIcon icon={'caret-down'} />
-                                                    </div>
-                                                </div>
-                                            </div>
-                                            <button
-                                                style={{ background: !targZoom || this.sourceAnchor?.followLinkZoomScale === 0 ? '' : '#4476f7', borderRadius: 3, gridColumn: 3 }}
-                                                onPointerDown={e => this.toggleAnchorProp(e, 'followLinkZoom', this.sourceAnchor)}
-                                                onClick={e => e.stopPropagation()}
-                                                className="propertiesButton">
-                                                <FontAwesomeIcon className="fa-icon" icon={faArrowRight as IconLookup} size="lg" />
-                                            </button>
-                                        </div>
-                                        {!targZoom ? null : PresBox.inputter('0', '1', '100', zoom, true, this.setZoom, 30)}
-                                        <div
-                                            className={'slider-headers'}
-                                            style={{
-                                                display: !targZoom ? 'none' : 'grid',
-                                                justifyContent: 'space-between',
-                                                width: `calc(100% - ${indent * 2}px)`,
-                                                marginLeft: indent,
-                                                marginRight: indent,
-                                                gridTemplateColumns: 'auto auto',
-                                                borderTop: 'solid',
-                                            }}>
-                                            <div className="slider-text">0%</div>
-                                            <div className="slider-text">100%</div>
-                                        </div>{' '}
-                                    </div>
-                                )}
-                            </>
+                            this.linkProperties
                         )}
-
                         {this.inkSubMenu}
-
                         {this.optionsSubMenu}
-
                         {this.fieldsSubMenu}
-
                         {isNovice ? null : this.sharingSubMenu}
-
                         {isNovice ? null : this.filtersSubMenu}
-
                         {isNovice ? null : this.layoutSubMenu}
                     </div>
                 );
@@ -1549,7 +1548,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                     : PresBox.targetRenderedDoc(PresBox.Instance.activeItem)?.type;
                 return (
                     <div className="propertiesView" style={{ width: this.props.width }}>
-                        <div className="propertiesView-title" style={{ width: this.props.width }}>
+                        <div className="propertiesView-sectionTitle" style={{ width: this.props.width }}>
                             Presentation
                         </div>
                         <div className="propertiesView-name" style={{ borderBottom: 0 }}>
@@ -1564,7 +1563,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                                 <div className="propertiesView-presTrails-title" onPointerDown={action(() => (this.openPresTransitions = !this.openPresTransitions))} style={{ backgroundColor: this.openPresTransitions ? 'black' : '' }}>
                                     &nbsp; <FontAwesomeIcon style={{ alignSelf: 'center' }} icon={'rocket'} /> &nbsp; Transitions
                                     <div className="propertiesView-presTrails-title-icon">
-                                        <FontAwesomeIcon icon={this.openPresTransitions ? 'caret-down' : 'caret-right'} size="lg" color="white" />
+                                        <FontAwesomeIcon icon={this.openPresTransitions ? 'caret-down' : 'caret-right'} size="lg"  />
                                     </div>
                                 </div>
                                 {this.openPresTransitions ? <div className="propertiesView-presTrails-content">{PresBox.Instance.transitionDropdown}</div> : null}
@@ -1578,7 +1577,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                                     style={{ backgroundColor: this.openPresTransitions ? 'black' : '' }}>
                                     &nbsp; <FontAwesomeIcon style={{ alignSelf: 'center' }} icon={'rocket'} /> &nbsp; Visibilty
                                     <div className="propertiesView-presTrails-title-icon">
-                                        <FontAwesomeIcon icon={this.openPresVisibilityAndDuration ? 'caret-down' : 'caret-right'} size="lg" color="white" />
+                                        <FontAwesomeIcon icon={this.openPresVisibilityAndDuration ? 'caret-down' : 'caret-right'} size="lg"  />
                                     </div>
                                 </div>
                                 {this.openPresVisibilityAndDuration ? <div className="propertiesView-presTrails-content">{PresBox.Instance.visibiltyDurationDropdown}</div> : null}
@@ -1589,7 +1588,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                                 <div className="propertiesView-presTrails-title" onPointerDown={action(() => (this.openPresProgressivize = !this.openPresProgressivize))} style={{ backgroundColor: this.openPresTransitions ? 'black' : '' }}>
                                     &nbsp; <FontAwesomeIcon style={{ alignSelf: 'center' }} icon={'rocket'} /> &nbsp; Progressivize
                                     <div className="propertiesView-presTrails-title-icon">
-                                        <FontAwesomeIcon icon={this.openPresProgressivize ? 'caret-down' : 'caret-right'} size="lg" color="white" />
+                                        <FontAwesomeIcon icon={this.openPresProgressivize ? 'caret-down' : 'caret-right'} size="lg"  />
                                     </div>
                                 </div>
                                 {this.openPresProgressivize ? <div className="propertiesView-presTrails-content">{PresBox.Instance.progressivizeDropdown}</div> : null}
@@ -1600,7 +1599,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                                 <div className="propertiesView-presTrails-title" onPointerDown={action(() => (this.openSlideOptions = !this.openSlideOptions))} style={{ backgroundColor: this.openSlideOptions ? 'black' : '' }}>
                                     &nbsp; <FontAwesomeIcon style={{ alignSelf: 'center' }} icon={type === DocumentType.AUDIO ? 'file-audio' : 'file-video'} /> &nbsp; {type === DocumentType.AUDIO ? 'Audio Options' : 'Video Options'}
                                     <div className="propertiesView-presTrails-title-icon">
-                                        <FontAwesomeIcon icon={this.openSlideOptions ? 'caret-down' : 'caret-right'} size="lg" color="white" />
+                                        <FontAwesomeIcon icon={this.openSlideOptions ? 'caret-down' : 'caret-right'} size="lg"  />
                                     </div>
                                 </div>
                                 {this.openSlideOptions ? <div className="propertiesView-presTrails-content">{PresBox.Instance.mediaOptionsDropdown}</div> : null}
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index 96502115d..472eefa6a 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -160,7 +160,9 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
                 ''
             );
         case StyleProp.Color:
-            if (MainView.Instance.LastButton === doc) return Colors.DARK_GRAY;
+            if (MainView.Instance.LastButton === doc) return Doc.UserDoc().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));
             if (docColor) return docColor;
             const docView = props?.DocumentView?.();
@@ -196,7 +198,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
                 ? 15
                 : 0;
         case StyleProp.BackgroundColor: {
-            if (MainView.Instance.LastButton === doc) return Colors.LIGHT_GRAY;
+            if (MainView.Instance.LastButton === 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) {
@@ -221,9 +223,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)
-                            ? darkScheme()
-                                ? undefined
-                                : undefined // system docs (seen in treeView) get a grayish background
+                            ? StrCast(Doc.UserDoc().userBackgroundColor)
                             : doc.annotationOn
                             ? '#00000010' // faint interior for collections on PDFs, images, etc
                             : doc?._isGroup
diff --git a/src/client/views/UndoStack.scss b/src/client/views/UndoStack.scss
index ab21e6d7e..192b99a12 100644
--- a/src/client/views/UndoStack.scss
+++ b/src/client/views/UndoStack.scss
@@ -2,9 +2,10 @@
     height: 100%;
     display: flex;
     flex-direction: column;
+    justify-content: center;
+    align-items: center;
     position: relative;
     pointer-events: all;
-    padding-left: 4px;
 }
 
 .undoStack-resultContainer {
@@ -21,9 +22,11 @@
 }
 
 .undoStack-commandsContainer {
-    background-color: whitesmoke;
     flex: 1 1 auto;
     overflow-y: scroll;
-    height: 30px;
+    height: fit-content;
+    width: 200px;
     border-radius: 5px;
+    padding: 5px;
+    max-height: 200px;
 }
diff --git a/src/client/views/UndoStack.tsx b/src/client/views/UndoStack.tsx
index f5af09e5b..28f1b8bd9 100644
--- a/src/client/views/UndoStack.tsx
+++ b/src/client/views/UndoStack.tsx
@@ -3,6 +3,9 @@ import { observer } from 'mobx-react';
 import * as React from 'react';
 import { UndoManager } from '../util/UndoManager';
 import './UndoStack.scss';
+import { StrCast } from '../../fields/Types';
+import { Doc } from '../../fields/Doc';
+import { Popup, Type } from 'browndash-components';
 
 interface UndoStackProps {
     width?: number;
@@ -15,32 +18,31 @@ export class UndoStack extends React.Component<UndoStackProps> {
     @observable static Expand: boolean;
     render() {
         return this.props.inline && UndoStack.HideInline ? null : (
-            <div
-                className="undoStack-outerContainer"
-                style={{ width: this.props.width, height: this.props.height ? (UndoStack.Expand ? 4 : 1) * this.props.height : undefined, top: UndoStack.Expand && this.props.height ? -this.props.height * 3 : undefined }}
-                onClick={action(e => (UndoStack.Expand = !UndoStack.Expand))}
-                onDoubleClick={action(e => (UndoStack.Expand = UndoStack.HideInline = false))}>
-                <div className="undoStack-commandsContainer" ref={r => r?.scroll({ behavior: 'auto', top: r?.scrollHeight + 20 })} style={{ background: UndoManager.batchCounter.get() ? 'yellow' : undefined }}>
-                    <div className="undoStack-resultContainer" key={0}>
-                        <div className="undoStack-commandString" style={{ fontWeight: 'bold', textAlign: 'center' }}>
-                            Undo/Redo Stack
-                        </div>
-                    </div>
-                    {UndoManager.undoStackNames.map((name, i) => (
-                        <div className="undoStack-resultContainer" key={i}>
-                            <div className="undoStack-commandString">{name.replace(/[^\.]*\./, '')}</div>
-                        </div>
-                    ))}
-                    {Array.from(UndoManager.redoStackNames)
-                        .reverse()
-                        .map((name, i) => (
+            <div className="undoStack-outerContainer">
+                <Popup 
+                    text={'Undo/Redo Stack'}
+                    color={StrCast(Doc.UserDoc().userVariantColor)}
+                    placement={`top-start`}
+                    type={Type.TERT}
+                    popup={
+                    <div className="undoStack-commandsContainer" ref={r => r?.scroll({ behavior: 'auto', top: r?.scrollHeight + 20 })} style={{ background: UndoManager.batchCounter.get() ? 'yellow' : undefined }}>
+                        {UndoManager.undoStackNames.map((name, i) => (
                             <div className="undoStack-resultContainer" key={i}>
-                                <div className="undoStack-commandString" style={{ fontWeight: 'bold', color: 'red' }}>
-                                    {name.replace(/[^\.]*\./, '')}
-                                </div>
+                                <div className="undoStack-commandString">{name.replace(/[^\.]*\./, '')}</div>
                             </div>
                         ))}
-                </div>
+                        {Array.from(UndoManager.redoStackNames)
+                            .reverse()
+                            .map((name, i) => (
+                                <div className="undoStack-resultContainer" key={i}>
+                                    <div className="undoStack-commandString" style={{ fontWeight: 'bold', color: 'red' }}>
+                                        {name.replace(/[^\.]*\./, '')}
+                                    </div>
+                                </div>
+                        ))}
+                    </div>    
+                    }
+                />
             </div>
         );
     }
diff --git a/src/client/views/collections/CollectionMenu.scss b/src/client/views/collections/CollectionMenu.scss
index 9db8fe532..6eeccc94e 100644
--- a/src/client/views/collections/CollectionMenu.scss
+++ b/src/client/views/collections/CollectionMenu.scss
@@ -10,650 +10,13 @@
     border-bottom: $standard-border;
     padding: 0 10px;
     align-items: center;
+    overflow-x: scroll;
+    &::-webkit-scrollbar {
+        display: none;
+    }
 
-    .collectionMenu-hardCodedButton {
-        cursor: pointer;
-        color: $white;
-        width: 25px;
-        height: 25px;
-        padding: 5;
-        text-align: center;
+    .hardCodedButtons {
         display: flex;
-        justify-content: center;
-        align-items: center;
-        position: relative;
-        transition: 0.2s;
-        border-radius: 3px;
-
-        &:hover {
-            background-color: rgba(0, 0, 0, 0.2);
-        }
+        flex-direction: row;
     }
-}
-
-// .collectionMenu-cont {
-//     position: relative;
-//     display: inline-flex;
-//     width: 100%;
-//     opacity: 0.9;
-//     z-index: 901;
-//     transition: top .5s;
-//     background: $dark-gray;
-//     color: $white;
-//     transform-origin: top left;
-//     top: 0;
-//     width: 100%;
-
-//     .recordButtonOutline {
-//         border-radius: 100%;
-//         width: 18px;
-//         height: 18px;
-//         border: solid 1px $white;
-//         display: flex;
-//         align-items: center;
-//         justify-content: center;
-//     }
-
-//     .recordButtonInner {
-//         border-radius: 100%;
-//         width: 70%;
-//         height: 70%;
-//         background: $white;
-//     }
-
-//     .collectionMenu {
-//         display: flex;
-//         height: 100%;
-//         overflow: visible;
-//         z-index: 901;
-//         border: unset;
-
-//         .collectionMenu-divider {
-//             height: 100%;
-//             margin-left: 3px;
-//             margin-right: 3px;
-//             width: 2px;
-//             background-color: $medium-gray;
-//         }
-
-//         .collectionViewBaseChrome {
-//             display: flex;
-//             align-items: center;
-
-//             .collectionViewBaseChrome-viewPicker {
-//                 font-size: $small-text;
-//                 outline-color: $black;
-//                 color: $white;
-//                 border: none;
-//                 background: $dark-gray;               
-//             }
-
-//             .collectionViewBaseChrome-viewPicker:focus {
-//                 outline: none;
-//                 border: none;
-//             }
-
-//             .collectionViewBaseChrome-viewPicker:active {
-//                 outline-color: $black;
-//             }
-
-//             .collectionViewBaseChrome-button {
-//                 font-size: $small-text;
-//                 text-transform: uppercase;
-//                 letter-spacing: 2px;
-//                 background: $white;
-//                 color: $pink;
-//                 outline-color: $black;
-//                 border: none;
-//                 padding: 12px 10px 11px 10px;
-//                 margin-left: 10px;
-//             }
-
-//             .collectionViewBaseChrome-cmdPicker {
-//                 margin-left: 3px;
-//                 margin-right: 0px;
-//                 font-size: $small-text;
-//                 text-transform: capitalize;
-//                 color: $white;
-//                 border: none;
-//                 background: $dark-gray;     
-//             }
-
-//             .collectionViewBaseChrome-cmdPicker:focus {
-//                 border: none;
-//                 outline: none;
-//             }
-
-//             .commandEntry-outerDiv {
-//                 pointer-events: all;
-//                 background-color: transparent;
-//                 display: flex;
-//                 flex-direction: row;
-//                 align-items: center;
-//                 justify-content: center;
-//                 height: 100%;
-//                 overflow: hidden;
-
-//                 .commandEntry-drop {
-//                     color: $white;
-//                     width: 30px;
-//                     margin-top: auto;
-//                     margin-bottom: auto;
-//                 }
-//             }
-
-//             .commandEntry-outerDiv:hover{
-//                 background-color: $drop-shadow;
-
-//                 .collectionViewBaseChrome-viewPicker,
-//                 .collectionViewBaseChrome-cmdPicker{
-//                     background: $dark-gray;
-//                 }
-//             }
-
-//             .collectionViewBaseChrome-collapse {
-//                 transition: all .5s, opacity 0.3s;
-//                 position: absolute;
-//                 width: 30px;
-//                 transform-origin: top left;
-//                 pointer-events: all;
-//                 // margin-top: 10px;
-//             }
-
-//             @media only screen and (max-device-width: 480px) {
-//                 .collectionViewBaseChrome-collapse {
-//                     display: none;
-//                 }
-//             }
-
-//             .collectionViewBaseChrome-template,
-//             .collectionViewBaseChrome-viewModes {
-//                 align-items: center;
-//                 height: 100%;
-//                 display: flex;
-//                 background: transparent;
-//                 color: $medium-gray;
-//                 justify-content: center;
-//             }
-
-//             .collectionViewBaseChrome-viewSpecs {
-//                 margin-left: 5px;
-//                 display: grid;
-//                 border: none;
-//                 border-right: solid $medium-gray 1px;
-
-//                 .collectionViewBaseChrome-filterIcon {
-//                     position: relative;
-//                     display: flex;
-//                     margin: auto;
-//                     background: $dark-gray;
-//                     color: $white;
-//                     width: 30px;
-//                     height: 30px;
-//                     align-items: center;
-//                     justify-content: center;
-//                     border: none;
-//                     border-right: solid $medium-gray 1px;
-//                 }
-
-//                 .collectionViewBaseChrome-viewSpecsInput {
-//                     padding: 12px 10px 11px 10px;
-//                     border: 0px;
-//                     color: $medium-gray;
-//                     text-align: center;
-//                     letter-spacing: 2px;
-//                     outline-color: $black;
-//                     font-size: $small-text;
-//                     background: $white;
-//                     height: 100%;
-//                     width: 75px;
-//                 }
-
-//                 .collectionViewBaseChrome-viewSpecsMenu {
-//                     overflow: hidden;
-//                     transition: height .5s, display .5s;
-//                     position: absolute;
-//                     top: 60px;
-//                     z-index: 100;
-//                     display: flex;
-//                     flex-direction: column;
-//                     background: $white;
-//                     box-shadow: $medium-gray 2px 2px 4px;
-
-//                     .qs-datepicker {
-//                         left: unset;
-//                         right: 0;
-//                     }
-
-//                     .collectionViewBaseChrome-viewSpecsMenu-row {
-//                         display: grid;
-//                         grid-template-columns: 150px 200px 150px;
-//                         margin-top: 10px;
-//                         margin-right: 10px;
-
-//                         .collectionViewBaseChrome-viewSpecsMenu-rowLeft,
-//                         .collectionViewBaseChrome-viewSpecsMenu-rowMiddle,
-//                         .collectionViewBaseChrome-viewSpecsMenu-rowRight {
-//                             font-size: $small-text;
-//                             letter-spacing: 2px;
-//                             color: $medium-gray;
-//                             margin-left: 10px;
-//                             padding: 5px;
-//                             border: none;
-//                             outline-color: $black;
-//                         }
-//                     }
-
-//                     .collectionViewBaseChrome-viewSpecsMenu-lastRow {
-//                         display: grid;
-//                         grid-template-columns: 1fr 1fr 1fr;
-//                         grid-gap: 10px;
-//                         margin: 10px;
-//                     }
-//                 }
-//             }
-//         }
-
-//         .collectionStackingViewChrome-cont,
-//         .collectionTreeViewChrome-cont,
-//         .collection3DCarouselViewChrome-cont {
-//             display: flex;
-//             justify-content: space-between;
-//         }
-
-//         .collectionGridViewChrome-cont {
-//             display: flex;
-//             margin-left: 10;
-
-//             .collectionGridViewChrome-viewPicker {
-//                 font-size: $small-text;
-//                 //text-transform: uppercase;
-//                 //letter-spacing: 2px;
-//                 background: $dark-gray;
-//                 color: $white;
-//                 outline-color: $black;
-//                 color: $white;
-//                 border: none;
-//                 border-right: solid $medium-gray 1px;
-//             }
-
-//             .collectionGridViewChrome-viewPicker:active {
-//                 outline-color: $black;
-//             }
-
-//             .grid-control {
-//                 align-self: center;
-//                 display: flex;
-//                 flex-direction: row;
-//                 margin-right: 5px;
-
-//                 .grid-icon {
-//                     margin-right: 5px;
-//                     align-self: center;
-//                 }
-
-//                 .flexLabel {
-//                     margin-bottom: 0;
-//                 }
-
-//                 .collectionGridViewChrome-entryBox {
-//                     width: 50%;
-//                     color: $black;
-//                 }
-
-//                 .collectionGridViewChrome-columnButton {
-//                     color: $black;
-//                 }
-//             }
-//         }
-
-//         .collectionStackingViewChrome-sort,
-//         .collectionTreeViewChrome-sort {
-//             display: flex;
-//             align-items: center;
-//             justify-content: space-between;
-
-//             .collectionStackingViewChrome-sortIcon,
-//             .collectionTreeViewChrome-sortIcon {
-//                 transition: transform .5s;
-//                 margin-left: 10px;
-//             }
-//         }
-
-//         button:hover {
-//             transform: scale(1);
-//         }
-
-
-//         .collectionStackingViewChrome-pivotField-cont,
-//         .collectionTreeViewChrome-pivotField-cont,
-//         .collection3DCarouselViewChrome-scrollSpeed-cont {
-//             justify-self: right;
-//             align-items: center;
-//             display: flex;
-//             grid-auto-columns: auto;
-//             font-size: $small-text;
-//             letter-spacing: 2px;
-
-//             .collectionStackingViewChrome-pivotField-label,
-//             .collectionTreeViewChrome-pivotField-label,
-//             .collection3DCarouselViewChrome-scrollSpeed-label {
-//                 grid-column: 1;
-//                 margin-right: 7px;
-//                 user-select: none;
-//                 font-family: $sans-serif;
-//                 letter-spacing: normal;
-//             }
-
-//             .collectionStackingViewChrome-sortIcon {
-//                 transition: transform .5s;
-//                 grid-column: 3;
-//                 text-align: center;
-//                 display: flex;
-//                 justify-content: center;
-//                 align-items: center;
-//                 cursor: pointer;
-//                 width: 25px;
-//                 height: 25px;
-//                 border-radius: 100%;
-//             }
-
-//             .collectionStackingViewChrome-sortIcon:hover {
-//                 background-color: $drop-shadow;
-//             }
-
-//             .collectionStackingViewChrome-pivotField,
-//             .collectionTreeViewChrome-pivotField,
-//             .collection3DCarouselViewChrome-scrollSpeed {
-//                 color: $white;
-//                 grid-column: 2;
-//                 grid-row: 1;
-//                 width: 90%;
-//                 min-width: 100px;
-//                 display: flex;
-//                 height: 80%;
-//                 border-radius: 7px;
-//                 align-items: center;
-//                 background: $white;
-
-//                 .editable-view-input,
-//                 input,
-//                 .editableView-container-editing-oneLine,
-//                 .editableView-container-editing {
-//                     margin: auto;
-//                     border: 0px;
-//                     color: $light-gray !important;
-//                     text-align: center;
-//                     letter-spacing: 2px;
-//                     outline-color: $black;
-//                     height: 100%;
-//                 }
-
-//                 .react-autosuggest__container {
-//                     margin: 0;
-//                     color: $medium-gray;
-//                     padding: 0px;
-//                 }
-//             }
-//         }
-
-//         .collectionStackingViewChrome-pivotField:hover,
-//         .collectionTreeViewChrome-pivotField:hover,
-//         .collection3DCarouselViewChrome-scrollSpeed:hover {
-//             cursor: text;
-//         }
-
-//     }
-// }
-
-// .collectionMenu-webUrlButtons {
-//     margin-left: 44;
-//     background: lightGray;
-//     display: flex;
-// }
-
-// .webBox-urlEditor {
-//     position: relative;
-//     opacity: 0.9;
-//     z-index: 901;
-//     transition: top .5s;
-
-//     .urlEditor {
-//         display: grid;
-//         grid-template-columns: 1fr auto;
-//         padding-bottom: 10px;
-//         overflow: hidden;
-//         margin-top: 5px;
-//         height: 35px;
-
-//         .editorBase {
-//             display: flex;
-
-//             .editor-collapse {
-//                 transition: all .5s, opacity 0.3s;
-//                 position: absolute;
-//                 width: 40px;
-//                 transform-origin: top left;
-//             }
-
-//             .switchToText {
-//                 color: $medium-gray;
-//             }
-
-//             .switchToText:hover {
-//                 color: $dark-gray;
-//             }
-//         }
-
-//         button:hover {
-//             transform: scale(1);
-//         }
-//     }
-// }
-
-// .collectionMenu-urlInput {
-//     padding: 12px 10px 11px 10px;
-//     border: 0px;
-//     color: $black;
-//     font-size: $small-text;
-//     letter-spacing: 2px;
-//     outline-color: $black;
-//     background: $white;
-//     width: 100%;
-//     min-width: 350px;
-//     margin-right: 10px;
-//     height: 100%;
-// }
-
-// .collectionFreeFormMenu-cont {
-//     display: inline-flex;
-//     position: relative;
-//     align-items: center;
-//     height: 100%;
-
-//     .color-previewI {
-//         width: 60%;
-//         top: 80%;
-//         position: absolute;
-//         height: 4px;
-//     }
-
-//     .color-previewII {
-//         width: 80%;
-//         height: 80%;
-//         margin-left: 10%;
-//         position: absolute;
-//         bottom: 5;
-//     }
-
-//     .btn-group {
-//         display: grid;
-//         grid-template-columns: auto auto auto auto;
-//         margin: auto;
-//         /* Make the buttons appear below each other */
-//     }
-
-//     .btn-draw {
-//         display: inline-flex;
-//         margin: auto;
-//         /* Make the buttons appear below each other */
-//     }
-
-//     .fwdKeyframe,
-//     .numKeyframe,
-//     .backKeyframe {
-//         cursor: pointer;
-//         position: relative;
-//         width: 20;
-//         height: 30;
-//         bottom: 0;
-//         background: $dark-gray;
-//         display: inline-flex;
-//         align-items: center;
-//         color: $white;
-//     }
-
-//     .backKeyframe {
-//         svg {
-//             display: block;
-//             margin: auto;
-//         }
-//     }
-
-
-//     .numKeyframe {
-//         flex-direction: column;
-//         padding-top: 5px;
-//     }
-
-//     .fwdKeyframe {
-//         svg {
-//             display: block;
-//             margin: auto;
-//         }
-
-//         border-right: solid $medium-gray 1px;
-//     }
-// }
-
-// .collectionSchemaViewChrome-cont {
-//     display: flex;
-//     font-size: $small-text;
-
-//     .collectionSchemaViewChrome-toggle {
-//         display: flex;
-//         margin-left: 10px;
-//     }
-
-//     .collectionSchemaViewChrome-label {
-//         text-transform: uppercase;
-//         letter-spacing: 2px;
-//         margin-right: 5px;
-//         display: flex;
-//         flex-direction: column;
-//         justify-content: center;
-//     }
-
-//     .collectionSchemaViewChrome-toggler {
-//         width: 100px;
-//         height: 35px;
-//         background-color: $black;
-//         position: relative;
-//     }
-
-//     .collectionSchemaViewChrome-togglerButton {
-//         width: 47px;
-//         height: 30px;
-//         background-color: $light-gray;
-//         // position: absolute;
-//         transition: all 0.5s ease;
-//         // top: 3px;
-//         margin-top: 3px;
-//         color: $medium-gray;
-//         letter-spacing: 2px;
-//         text-transform: uppercase;
-//         display: flex;
-//         flex-direction: column;
-//         justify-content: center;
-//         text-align: center;
-
-//         &.on {
-//             margin-left: 3px;
-//         }
-
-//         &.off {
-//             margin-left: 50px;
-//         }
-//     }
-// }
-
-
-// .commandEntry-outerDiv {
-//     display: flex;
-//     flex-direction: column;
-//     height: 40px;
-// }
-
-// .commandEntry-inputArea {
-//     display: flex;
-//     flex-direction: row;
-//     width: 150px;
-//     margin: auto auto auto auto;
-// }
-
-// .react-autosuggest__container {
-//     position: relative;
-//     width: 100%;
-//     margin-left: 5px;
-//     margin-right: 5px;
-// }
-
-// .react-autosuggest__input {
-//     border: 1px solid $light-gray;
-//     border-radius: 4px;
-//     width: 100%;
-// }
-
-// .react-autosuggest__input--focused {
-//     outline: none;
-// }
-
-// .react-autosuggest__input--open {
-//     border-bottom-left-radius: 0;
-//     border-bottom-right-radius: 0;
-// }
-
-// .react-autosuggest__suggestions-container {
-//     display: none;
-// }
-
-// .react-autosuggest__suggestions-container--open {
-//     display: block;
-//     position: fixed;
-//     overflow-y: auto;
-//     max-height: 400px;
-//     width: 180px;
-//     border: 1px solid $light-gray;
-//     background-color: $white;
-//     font-family: $sans-serif;
-//     font-weight: 300;
-//     font-size: $large-header;
-//     border-bottom-left-radius: 4px;
-//     border-bottom-right-radius: 4px;
-//     z-index: 2;
-// }
-
-// .react-autosuggest__suggestions-list {
-//     margin: 0;
-//     padding: 0;
-//     list-style-type: none;
-// }
-
-// .react-autosuggest__suggestion {
-//     cursor: pointer;
-//     padding: 10px 20px;
-// }
-
-// .react-autosuggest__suggestion--highlighted {
-//     background-color: $light-gray;
-// }
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 38692b924..9eb716763 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -2,23 +2,23 @@ import React = require('react');
 import { IconProp } from '@fortawesome/fontawesome-svg-core';
 import { FontAwesomeIcon, FontAwesomeIconProps } from '@fortawesome/react-fontawesome';
 import { Tooltip } from '@material-ui/core';
-import { action, computed, Lambda, observable, reaction, runInAction } from 'mobx';
+import { Toggle, ToggleType, Type } from 'browndash-components';
+import { Lambda, action, computed, observable, reaction, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
 import { ColorState } from 'react-color';
+import { Utils, emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, setupMoveUpEvents } from '../../../Utils';
 import { Doc, DocListCast, Opt } from '../../../fields/Doc';
-import { Document } from '../../../fields/documentSchemas';
 import { Id } from '../../../fields/FieldSymbols';
 import { InkTool } from '../../../fields/InkField';
 import { List } from '../../../fields/List';
 import { ObjectField } from '../../../fields/ObjectField';
 import { RichTextField } from '../../../fields/RichTextField';
 import { listSpec } from '../../../fields/Schema';
-import { ScriptField } from '../../../fields/ScriptField';
 import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../fields/Types';
+import { Document } from '../../../fields/documentSchemas';
 import { GestureUtils } from '../../../pen-gestures/GestureUtils';
-import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, setupMoveUpEvents, Utils } from '../../../Utils';
-import { Docs } from '../../documents/Documents';
 import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes';
+import { Docs } from '../../documents/Documents';
 import { DragManager } from '../../util/DragManager';
 import { ScriptingGlobals } from '../../util/ScriptingGlobals';
 import { SelectionManager } from '../../util/SelectionManager';
@@ -28,21 +28,19 @@ import { undoBatch } from '../../util/UndoManager';
 import { AntimodeMenu } from '../AntimodeMenu';
 import { EditableView } from '../EditableView';
 import { GestureOverlay } from '../GestureOverlay';
-import { Colors } from '../global/globalEnums';
 import { ActiveFillColor, ActiveInkColor, SetActiveArrowEnd, SetActiveArrowStart, SetActiveBezierApprox, SetActiveFillColor, SetActiveInkColor, SetActiveInkWidth } from '../InkingStroke';
 import { LightboxView } from '../LightboxView';
+import { MainView } from '../MainView';
+import { DefaultStyleProvider } from '../StyleProvider';
 import { CollectionFreeFormDocumentView } from '../nodes/CollectionFreeFormDocumentView';
 import { DocumentView, OpenWhereMod } from '../nodes/DocumentView';
-import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox';
 import { RichTextMenu } from '../nodes/formattedText/RichTextMenu';
-import { DefaultStyleProvider } from '../StyleProvider';
 import { CollectionDockingView } from './CollectionDockingView';
-import { CollectionLinearView } from './collectionLinear';
 import './CollectionMenu.scss';
 import { COLLECTION_BORDER_WIDTH } from './CollectionView';
 import { TabDocView } from './TabDocView';
 import { CollectionFreeFormView } from './collectionFreeForm';
-import { Group, IconButton, Toggle, ToggleType, Type } from 'browndash-components';
+import { CollectionLinearView } from './collectionLinear';
 
 interface CollectionMenuProps {
     panelHeight: () => number;
@@ -96,6 +94,15 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> {
         }
     };
 
+    @action
+    toggleProperties = () => {
+        if (MainView.Instance.propertiesWidth() > 0) {
+            SettingsManager.propertiesWidth = 0;
+        } else {
+            SettingsManager.propertiesWidth = 300;
+        }
+    };
+
     buttonBarXf = () => {
         if (!this._docBtnRef.current) return Transform.Identity();
         const { scale, translateX, translateY } = Utils.GetScreenTransform(this._docBtnRef.current);
@@ -140,18 +147,30 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> {
     }
 
     render() {
-        const propIcon = SettingsManager.headerBarHeight > 0 ? 'angle-double-up' : 'angle-double-down';
-        const propTitle = SettingsManager.headerBarHeight > 0 ? 'Close Header Bar' : 'Open Header Bar';
+        const headerIcon = SettingsManager.headerBarHeight > 0 ? 'angle-double-up' : 'angle-double-down';
+        const headerTitle = SettingsManager.headerBarHeight > 0 ? 'Close Header Bar' : 'Open Header Bar';
+        const propIcon = SettingsManager.propertiesWidth > 0 ? 'angle-double-right' : 'angle-double-left';
+        const propTitle = SettingsManager.propertiesWidth > 0 ? 'Close Properties' : 'Open Properties';
 
         const hardCodedButtons = (
             <div className={`hardCodedButtons`}>
                 <Toggle 
                     toggleType={ToggleType.BUTTON} 
                     type={Type.PRIM} 
-                    color={Colors.LIGHT_GRAY} 
+                    color={StrCast(Doc.UserDoc().userColor)} 
                     onClick={this.toggleTopBar} 
                     toggleStatus={SettingsManager.headerBarHeight > 0} 
+                    icon={<FontAwesomeIcon icon={headerIcon} size="lg" />}
+                    tooltip={headerTitle}
+                />
+                <Toggle 
+                    toggleType={ToggleType.BUTTON} 
+                    type={Type.PRIM}
+                    color={StrCast(Doc.UserDoc().userColor)} 
+                    onClick={this.toggleProperties} 
+                    toggleStatus={SettingsManager.propertiesWidth > 0} 
                     icon={<FontAwesomeIcon icon={propIcon} size="lg" />}
+                    tooltip={propTitle}
                 />
             </div>
         );
@@ -159,7 +178,11 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> {
         // NEW BUTTONS
         //dash col linear view buttons
         const contMenuButtons = (
-            <div className="collectionMenu-container">
+            <div className="collectionMenu-container" 
+            style={{
+                background: StrCast(Doc.UserDoc().userBackgroundColor),
+                // borderColor: StrCast(Doc.UserDoc().userColor)
+            }} >
                 {this.contMenuButtons}
                 {hardCodedButtons}
             </div>
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 4cd3885f5..09be9dc76 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -386,6 +386,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
     @observable _headerHeight = 0;
     @computed get content() {
         const background = () => this.props.styleProvider?.(this.doc, this.props, StyleProp.BackgroundColor);
+        const color = () => this.props.styleProvider?.(this.doc, this.props, StyleProp.Color);
         const pointerEvents = () => (this.props.isContentActive() === false ? 'none' : undefined);
         const titleBar = this.props.treeViewHideTitle || this.doc.treeViewHideTitle ? null : this.titleBar;
         return (
@@ -402,6 +403,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
                     ref={r => !this.doc.treeViewHasOverlay && r && this.createTreeDropTarget(r)}
                     style={{
                         ...(!titleBar ? { marginLeft: this.marginX(), paddingTop: this.marginTop() } : {}),
+                        color: color(),
                         overflow: 'auto',
                         width: '100%',
                         height: '100%',
diff --git a/src/client/views/collections/TabDocView.scss b/src/client/views/collections/TabDocView.scss
index 58605c3f4..13bb3a577 100644
--- a/src/client/views/collections/TabDocView.scss
+++ b/src/client/views/collections/TabDocView.scss
@@ -65,11 +65,7 @@ input.lm_title {
 }
 
 .miniMap {
-    position: absolute;
     overflow: hidden;
-    right: 15;
-    bottom: 15;
-    border: solid 1px;
     width: 100%;
     height: 100%;
     transition: all 0.5s;
@@ -90,18 +86,5 @@ input.lm_title {
     cursor: pointer;
     position: absolute;
     bottom: 5;
-    display: flex;
     right: 5;
-    width: 25px;
-    height: 25px;
-    border-radius: 3px;
-    padding: 2px;
-    justify-content: center;
-    align-items: center;
-    align-content: center;
-    background-color: $light-gray;
-
-    &:hover {
-        box-shadow: none;
-    }
 }
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 4d780f46b..714619a74 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -34,6 +34,7 @@ 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 {
@@ -573,63 +574,53 @@ export class TabMinimapView extends React.Component<TabMinimapViewProps> {
         const miniTop = 50 + ((NumCast(this.props.document._freeform_panY) - this.renderBounds.cy) / this.renderBounds.dim) * 100 - miniHeight / 2;
         const miniSize = this.returnMiniSize();
         return (
-            <>
-                {' '}
-                {this.props.document?.layout_hideMinimap ? null : (
-                    <div className="miniMap" style={{ width: miniSize, height: miniSize, background: this.props.background() }}>
-                        <CollectionFreeFormView
-                            Document={this.props.document}
-                            docViewPath={returnEmptyDoclist}
-                            childLayoutTemplate={this.childLayoutTemplate} // bcz: Ugh .. should probably be rendering a CollectionView or the minimap should be part of the collectionFreeFormView to avoid having to set stuff like this.
-                            noOverlay={true} // don't render overlay Docs since they won't scale
-                            setHeight={returnFalse}
-                            isContentActive={emptyFunction}
-                            isAnyChildContentActive={returnFalse}
-                            select={emptyFunction}
-                            isSelected={returnFalse}
-                            dontRegisterView={true}
-                            fieldKey={Doc.LayoutFieldKey(this.props.document)}
-                            bringToFront={emptyFunction}
-                            rootSelected={returnTrue}
-                            addDocument={returnFalse}
-                            moveDocument={returnFalse}
-                            removeDocument={returnFalse}
-                            PanelWidth={this.returnMiniSize}
-                            PanelHeight={this.returnMiniSize}
-                            ScreenToLocalTransform={Transform.Identity}
-                            renderDepth={0}
-                            whenChildContentsActiveChanged={emptyFunction}
-                            focus={emptyFunction}
-                            styleProvider={TabMinimapView.miniStyleProvider}
-                            addDocTab={this.props.addDocTab}
-                            pinToPres={TabDocView.PinDoc}
-                            childFilters={CollectionDockingView.Instance?.childDocFilters ?? returnEmptyDoclist}
-                            childFiltersByRanges={CollectionDockingView.Instance?.childDocRangeFilters ?? returnEmptyDoclist}
-                            searchFilterDocs={CollectionDockingView.Instance?.searchFilterDocs ?? returnEmptyDoclist}
-                            fitContentsToBox={returnTrue}
-                        />
-                        <div className="miniOverlay" onPointerDown={this.miniDown}>
-                            <div className="miniThumb" style={{ width: `${miniWidth}% `, height: `${miniHeight}% `, left: `${miniLeft}% `, top: `${miniTop}% ` }} />
+            <div className="miniMap-hidden">
+                <Popup
+                    icon={<FontAwesomeIcon icon="globe-asia" size="lg" />}
+                    color={StrCast(Doc.UserDoc().userVariantColor, Colors.MEDIUM_BLUE)}
+                    type={Type.TERT}
+                    onPointerDown={e => e.stopPropagation()}
+                    placement={'top-end'}
+                    popup={
+                        <div className="miniMap" style={{ width: miniSize, height: miniSize, background: this.props.background() }}>
+                            <CollectionFreeFormView
+                                Document={this.props.document}
+                                docViewPath={returnEmptyDoclist}
+                                childLayoutTemplate={this.childLayoutTemplate} // bcz: Ugh .. should probably be rendering a CollectionView or the minimap should be part of the collectionFreeFormView to avoid having to set stuff like this.
+                                noOverlay={true} // don't render overlay Docs since they won't scale
+                                setHeight={returnFalse}
+                                isContentActive={emptyFunction}
+                                isAnyChildContentActive={returnFalse}
+                                select={emptyFunction}
+                                isSelected={returnFalse}
+                                dontRegisterView={true}
+                                fieldKey={Doc.LayoutFieldKey(this.props.document)}
+                                bringToFront={emptyFunction}
+                                rootSelected={returnTrue}
+                                addDocument={returnFalse}
+                                moveDocument={returnFalse}
+                                removeDocument={returnFalse}
+                                PanelWidth={this.returnMiniSize}
+                                PanelHeight={this.returnMiniSize}
+                                ScreenToLocalTransform={Transform.Identity}
+                                renderDepth={0}
+                                whenChildContentsActiveChanged={emptyFunction}
+                                focus={emptyFunction}
+                                styleProvider={TabMinimapView.miniStyleProvider}
+                                addDocTab={this.props.addDocTab}
+                                pinToPres={TabDocView.PinDoc}
+                                childFilters={CollectionDockingView.Instance?.childDocFilters ?? returnEmptyDoclist}
+                                childFiltersByRanges={CollectionDockingView.Instance?.childDocRangeFilters ?? returnEmptyDoclist}
+                                searchFilterDocs={CollectionDockingView.Instance?.searchFilterDocs ?? returnEmptyDoclist}
+                                fitContentsToBox={returnTrue}
+                            />
+                            <div className="miniOverlay" onPointerDown={this.miniDown}>
+                                <div className="miniThumb" style={{ width: `${miniWidth}% `, height: `${miniHeight}% `, left: `${miniLeft}% `, top: `${miniTop}% ` }} />
+                            </div>
                         </div>
-                    </div>
-                )}
-                <Tooltip key="ttip" title={<div className="dash-tooltip">{this.props.document.layout_hideMinimap ? 'Open minimap' : 'Close minimap'}</div>}>
-                    <div
-                        className="miniMap-hidden"
-                        style={{
-                            color: this.props.document.layout_hideMinimap ? Colors.BLACK : Colors.WHITE,
-                            backgroundColor: this.props.document.layout_hideMinimap ? Colors.LIGHT_GRAY : Colors.MEDIUM_BLUE,
-                            boxShadow: this.props.document.layout_hideMinimap ? Shadows.STANDARD_SHADOW : undefined,
-                        }}
-                        onPointerDown={e => e.stopPropagation()}
-                        onClick={action(e => {
-                            e.stopPropagation();
-                            this.props.document!.layout_hideMinimap = !this.props.document!.layout_hideMinimap;
-                        })}>
-                        <FontAwesomeIcon icon="globe-asia" size="lg" />
-                    </div>
-                </Tooltip>
-            </>
+                    }
+                />
+            </div>
         );
     }
 }
diff --git a/src/client/views/collections/TreeView.scss b/src/client/views/collections/TreeView.scss
index 7eab03e1d..85f99b9c2 100644
--- a/src/client/views/collections/TreeView.scss
+++ b/src/client/views/collections/TreeView.scss
@@ -24,34 +24,18 @@
         // width: $TREE_BULLET_WIDTH;
         width: 100%;
         height: 100%;
-        position: absolute;
-
-        .treeView-expandIcon {
-            display: none;
-            left: -10px;
-            position: absolute;
-        }
-
-        .treeView-checkIcon {
-            left: 3.5px;
-            top: 2px;
-            position: absolute;
-        }
-
-        &:hover {
-            .treeView-expandIcon {
-                display: unset;
-            }
-        }
+        position: relative;
+        display: flex;
+        flex-direction: row;
     }
 
-    .treeView-bulletIcons:hover img {
-        left: 14px;
-        position: absolute;
-        transform-origin: center left;
-        transform: scale(6);
-        pointer-events: none;
-    }
+    // .treeView-bulletIcons:hover img {
+    //     left: 14px;
+    //     position: absolute;
+    //     transform-origin: center left;
+    //     transform: scale(6);
+    //     pointer-events: none;
+    // }
 
     .bullet {
         grid-column: 1;
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 8d8d895c6..55f62cdf2 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -34,6 +34,7 @@ import { CollectionTreeView, TreeViewType } from './CollectionTreeView';
 import { CollectionView } from './CollectionView';
 import './TreeView.scss';
 import React = require('react');
+import { IconButton, Size } from 'browndash-components';
 
 export interface TreeViewProps {
     treeView: CollectionTreeView;
@@ -541,6 +542,8 @@ export class TreeView extends React.Component<TreeViewProps> {
         TraceMobx();
         const expandKey = this.treeViewExpandedView;
         const sortings = (this.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.TreeViewSortings) as { [key: string]: { color: string; label: string } }) ?? {};
+        const color = this.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.Color)
+        console.log("tree view", color, this.doc.title, Doc.IsSystem(this.doc))
         if (['links', 'annotations', 'embeddings', this.fieldKey].includes(expandKey)) {
             const sorting = StrCast(this.doc.treeViewSortCriterion, TreeSort.None);
             const sortKeys = Object.keys(sortings);
@@ -580,7 +583,9 @@ export class TreeView extends React.Component<TreeViewProps> {
                 );
             }
             return (
-                <>
+                <div style={{ 
+                    color: color
+                 }}>
                     {!docs?.length || this.props.AddToMap /* hack to identify pres box trees */ ? null : (
                         <div className={'treeView-sorting'} style={{ background: sortings[sorting]?.color }}>
                             {sortings[sorting]?.label}
@@ -640,17 +645,18 @@ export class TreeView extends React.Component<TreeViewProps> {
                                   this._renderCount
                               )}
                     </ul>
-                </>
+                </div>
             );
         } else if (this.treeViewExpandedView === 'fields') {
             return (
-                <ul key={this.doc[Id] + this.doc.title} style={{ cursor: 'inherit' }}>
+                <ul key={this.doc[Id] + this.doc.title} style={{ cursor: 'inherit', color: color }}>
                     <div>{this.expandedField}</div>
                 </ul>
             );
         }
         return (
             <ul
+                style={{ color: color }}
                 onPointerDown={e => {
                     e.preventDefault();
                     e.stopPropagation();
@@ -685,6 +691,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 = this.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.Color)
         const checked = this.onCheckedClick ? this.doc.treeViewChecked ?? 'unchecked' : undefined;
         return (
             <div
@@ -705,14 +712,26 @@ export class TreeView extends React.Component<TreeViewProps> {
                 }>
                 {this.props.treeView.outlineMode ? (
                     !(this.doc.text as RichTextField)?.Text ? null : (
-                        <FontAwesomeIcon size="sm" icon={[this.childDocs?.length && !this.treeViewOpen ? 'fas' : 'far', 'circle']} />
+                        <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-${this.onCheckedClick ? 'checkIcon' : 'expandIcon'}`}>
-                            <FontAwesomeIcon size="sm" 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}
+                        <IconButton
+                            color={color} 
+                            icon={<FontAwesomeIcon size="sm" icon={checked === 'check' ? 'check' : checked === 'x' ? 'times' : checked === 'unchecked' ? 'square' : !this.treeViewOpen ? 'caret-right' : 'caret-down'} />}
+                            size={Size.XSMALL}
+                        />
+                        {this.onCheckedClick ? null : 
+                        <IconButton
+                            color={color} 
+                            icon={<FontAwesomeIcon icon={iconType as IconProp} />}
+                            size={Size.XSMALL}
+                        />
+                        }
                     </div>
                 )}
             </div>
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx
index c9168d40a..0f51fe6ff 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx
@@ -4,6 +4,10 @@ import { Tooltip } from '@material-ui/core';
 import { observer } from 'mobx-react';
 import { unimplementedFunction } from '../../../../Utils';
 import { AntimodeMenu, AntimodeMenuProps } from '../../AntimodeMenu';
+import { IconButton } from 'browndash-components';
+import { StrCast } from '../../../../fields/Types';
+import { Doc } from '../../../../fields/Doc';
+import { computed } from 'mobx';
 
 @observer
 export class MarqueeOptionsMenu extends AntimodeMenu<AntimodeMenuProps> {
@@ -22,39 +26,44 @@ export class MarqueeOptionsMenu extends AntimodeMenu<AntimodeMenuProps> {
         MarqueeOptionsMenu.Instance = this;
     }
 
+    @computed get userColor() {
+        return StrCast(Doc.UserDoc().userColor)
+    }
+
     render() {
-        const presPinWithViewIcon = <img src="/assets/pinWithView.png" style={{ margin: 'auto', width: 19, transform: 'translate(-2px, -2px)' }} />;
+        const presPinWithViewIcon = <img src="/assets/pinWithView.png" style={{ width: 19 }} />;
         const buttons = (
             <>
-                <Tooltip key="collect" title={<div className="dash-tooltip">Create a Collection</div>} placement="bottom">
-                    <button className="antimodeMenu-button" onPointerDown={this.createCollection}>
-                        <FontAwesomeIcon icon="object-group" size="lg" />
-                    </button>
-                </Tooltip>
-                ,
-                <Tooltip key="group" title={<div className="dash-tooltip">Create a Grouping</div>} placement="bottom">
-                    <button className="antimodeMenu-button" onPointerDown={e => this.createCollection(e, true)}>
-                        <FontAwesomeIcon icon="layer-group" size="lg" />
-                    </button>
-                </Tooltip>
-                ,
-                <Tooltip key="summarize" title={<div className="dash-tooltip">Summarize Documents</div>} placement="bottom">
-                    <button className="antimodeMenu-button" onPointerDown={this.summarize}>
-                        <FontAwesomeIcon icon="compress-arrows-alt" size="lg" />
-                    </button>
-                </Tooltip>
-                ,
-                <Tooltip key="delete" title={<div className="dash-tooltip">Delete Documents</div>} placement="bottom">
-                    <button className="antimodeMenu-button" onPointerDown={this.delete}>
-                        <FontAwesomeIcon icon="trash-alt" size="lg" />
-                    </button>
-                </Tooltip>
-                ,
-                <Tooltip key="pinWithView" title={<div className="dash-tooltip">Pin selected region to trail</div>} placement="bottom">
-                    <button className="antimodeMenu-button" onPointerDown={this.pinWithView}>
-                        {presPinWithViewIcon}
-                    </button>
-                </Tooltip>
+                <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={presPinWithViewIcon}
+                    color={this.userColor}
+                />
             </>
         );
         return this.getElement(buttons);
diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
index 446e720e8..56b8366d0 100644
--- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
+++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
@@ -20,7 +20,8 @@ import { UndoStack } from '../../UndoStack';
 import { CollectionStackedTimeline } from '../CollectionStackedTimeline';
 import { CollectionSubView } from '../CollectionSubView';
 import './CollectionLinearView.scss';
-import { Button, Type } from 'browndash-components';
+import { Button, Toggle, ToggleType, Type } from 'browndash-components';
+import { Colors } from '../../global/globalEnums';
 
 /**
  * CollectionLinearView is the class for rendering the horizontal collection
@@ -47,7 +48,7 @@ export class CollectionLinearView extends CollectionSubView() {
 
     componentDidMount() {
         this._widthDisposer = reaction(
-            () => 5 + NumCast(this.rootDoc.linearBtnWidth, this.dimension()) + (this.layoutDoc.linearView_IsExpanded ? this.childDocs.filter(doc => !doc.hidden).reduce((tot, doc) => (doc[Width]() || this.dimension()) + tot + 4, 0) : 0),
+            () => 5 + NumCast(this.rootDoc.linearBtnWidth, this.dimension()) + (this.layoutDoc.linearView_IsOpen ? this.childDocs.filter(doc => !doc.hidden).reduce((tot, doc) => (doc[Width]() || this.dimension()) + tot + 4, 0) : 0),
             width => this.childDocs.length && (this.layoutDoc._width = width),
             { fireImmediately: true }
         );
@@ -199,36 +200,48 @@ export class CollectionLinearView extends CollectionSubView() {
     render() {
         const flexDir = StrCast(this.Document.flexDirection); // Specify direction of linear view content
         const flexGap = NumCast(this.Document.flexGap); // Specify the gap between linear view content
-        const isExpanded = BoolCast(this.layoutDoc.linearView_IsExpanded);
+        const isExpanded = BoolCast(this.layoutDoc.linearView_IsOpen);
 
         const menuOpener = (
-            <Button 
+            <Toggle
                 text={Cast(this.props.Document.icon, 'string', null)} 
-                icon={<FontAwesomeIcon icon={isExpanded ? 'minus' : 'plus'} />}
+                icon={Cast(this.props.Document.icon, 'string', null) ? undefined : <FontAwesomeIcon icon={isExpanded ? 'minus' : 'plus'} />}
                 type={Type.TERT}
+                color={StrCast(Doc.UserDoc().userVariantColor, Colors.MEDIUM_BLUE)}
                 onPointerDown={e => e.stopPropagation()}
+                toggleType={ToggleType.BUTTON}
+                toggleStatus={BoolCast(this.layoutDoc.linearView_IsOpen)}
                 onClick={() => {
-                        this.layoutDoc.linearView_IsExpanded = !isExpanded;
+                        this.layoutDoc.linearView_IsOpen = !isExpanded;
                 }}
                 tooltip={isExpanded ? 'Close' : 'Open'}
+                fillWidth={true}
+                align={'center'}
             />
         );
 
         return (
-            <div className={`collectionLinearView-outer ${this.layoutDoc.linearView_SubMenu}`} style={{ backgroundColor: this.layoutDoc.linearView_IsExpanded ? undefined : 'transparent' }}>
+            <div className={`collectionLinearView-outer ${this.layoutDoc.linearView_SubMenu}`} style={{ backgroundColor: this.layoutDoc.linearView_IsOpen ? undefined : 'transparent' }}>
                 <div className="collectionLinearView" ref={this.createDashEventsTarget} onContextMenu={this.myContextMenu} style={{ minHeight: this.dimension(), pointerEvents: 'all' }}>
-                    {!this.props.Document.linearView_Expandable ? null : menuOpener}
-                    {!this.layoutDoc.linearView_IsExpanded ? null : (
-                        <div
-                            className="collectionLinearView-content"
-                            style={{
-                                height: this.dimension(),
-                                flexDirection: flexDir as any,
-                                gap: flexGap,
-                            }}>
-                            {this.childLayoutPairs.map(pair => this.getDisplayDoc(pair.layout))}
-                        </div>
-                    )}
+                    {this.props.Document.linearView_Dropdown ? 
+                        <div>Hello World!</div>
+                        : 
+                        <>
+                        {!this.props.Document.linearView_Expandable ? null : menuOpener}
+                        {!this.layoutDoc.linearView_IsOpen ? null : (
+                            <div
+                                className="collectionLinearView-content"
+                                style={{
+                                    height: this.dimension(),
+                                    flexDirection: flexDir as any,
+                                    gap: flexGap,
+                                }}>
+                                {this.childLayoutPairs.map(pair => this.getDisplayDoc(pair.layout))}
+                            </div>
+                        )}
+                        </>
+                    }
+                    
                 </div>
             </div>
         );
diff --git a/src/client/views/global/globalScripts.ts b/src/client/views/global/globalScripts.ts
index 8f6d898fe..d22b6b4d9 100644
--- a/src/client/views/global/globalScripts.ts
+++ b/src/client/views/global/globalScripts.ts
@@ -66,19 +66,20 @@ ScriptingGlobals.add(function setBackgroundColor(color?: string, checkResult?: b
 // toggle: Set overlay status of selected document
 ScriptingGlobals.add(function setHeaderColor(color?: string, checkResult?: boolean) {
     if (checkResult) {
-        return Doc.SharingDoc().userColor;
+        return Doc.SharingDoc().headingColor;
     }
-    Doc.SharingDoc().userColor = undefined;
-    Doc.GetProto(Doc.SharingDoc()).userColor = color;
+    Doc.SharingDoc().headingColor = undefined;
+    Doc.GetProto(Doc.SharingDoc()).headingColor = color;
     Doc.UserDoc().layout_showTitle = color === 'transparent' ? undefined : StrCast(Doc.UserDoc().layout_showTitle, 'author_date');
 });
 
 // toggle: Set overlay status of selected document
 ScriptingGlobals.add(function toggleOverlay(checkResult?: boolean) {
+    console.log(checkResult);
     const selected = SelectionManager.Views().length ? SelectionManager.Views()[0] : undefined;
     if (checkResult) {
-        if (NumCast(selected?.Document.z) >= 1) return Colors.MEDIUM_BLUE;
-        return 'transparent';
+        if (NumCast(selected?.Document.z) >= 1) return true;
+        return false;
     }
     selected ? selected.props.CollectionFreeFormDocumentView?.().float() : console.log('[FontIconBox.tsx] toggleOverlay failed');
 });
@@ -88,45 +89,47 @@ ScriptingGlobals.add(function showFreeform(attr: 'flashcards' | 'grid' | 'snapli
     // prettier-ignore
     const map: Map<'flashcards' | 'grid' | 'snaplines' | 'clusters' | 'arrange'| 'viewAll', { waitForRender?: boolean, checkResult: (doc:Doc) => any; setDoc: (doc:Doc) => void;}> = new Map([
         ['grid', {
-            checkResult: (doc:Doc) => doc._freeform_backgroundGrid,
+            checkResult: (doc:Doc) => BoolCast(doc._freeform_backgroundGrid, false),
             setDoc: (doc:Doc) => doc._freeform_backgroundGrid = !doc._freeform_backgroundGrid,
         }],
         ['snaplines', {
-            checkResult: (doc:Doc) => doc._freeform_snapLines,
+            checkResult: (doc:Doc) => BoolCast(doc._freeform_snapLines, false),
             setDoc: (doc:Doc) => doc._freeform_snapLines = !doc._freeform_snapLines,
         }],
         ['viewAll', {
-            checkResult: (doc:Doc) => doc._freeform_fitContentsToBox,
+            checkResult: (doc:Doc) => BoolCast(doc._freeform_fitContentsToBox, false),
             setDoc: (doc:Doc) => doc._freeform_fitContentsToBox = !doc._freeform_fitContentsToBox,
         }],
         ['clusters', {
             waitForRender: true, // flags that undo batch should terminate after a re-render giving the script the chance to fire
-            checkResult: (doc:Doc) => doc._freeform_useClusters,
+            checkResult: (doc:Doc) => BoolCast(doc._freeform_useClusters, false),
             setDoc: (doc:Doc) => doc._freeform_useClusters = !doc._freeform_useClusters,
         }],
         ['arrange', {
             waitForRender: true, // flags that undo batch should terminate after a re-render giving the script the chance to fire
-            checkResult: (doc:Doc) => doc._autoArrange,
+            checkResult: (doc:Doc) => BoolCast(doc._autoArrange, false),
             setDoc: (doc:Doc) => doc._autoArrange = !doc._autoArrange,
         }],
         ['flashcards', {
-            checkResult: (doc:Doc) => Doc.UserDoc().defaultToFlashcards,
+            checkResult: (doc:Doc) => BoolCast(Doc.UserDoc().defaultToFlashcards, false),
             setDoc: (doc:Doc) => Doc.UserDoc().defaultToFlashcards = !Doc.UserDoc().defaultToFlashcards,
         }],
    ]);
 
     if (checkResult) {
-        return map.get(attr)?.checkResult(selected) ? Colors.MEDIUM_BLUE : 'transparent';
+        console.log(attr, map.get(attr)?.checkResult(selected))
+        return map.get(attr)?.checkResult(selected);
     }
     const batch = map.get(attr)?.waitForRender ? UndoManager.StartBatch('set freeform attribute') : { end: () => {} };
     SelectionManager.Docs().map(dv => map.get(attr)?.setDoc(dv));
     setTimeout(() => batch.end(), 100);
 });
-ScriptingGlobals.add(function setFontAttr(attr: 'font' | 'fontColor' | 'highlight' | 'fontSize', value: any, checkResult?: boolean) {
+
+ScriptingGlobals.add(function setFontAttr(attr: 'font' | 'fontColor' | 'highlight' | 'fontSize' | 'alignment', value: any, checkResult?: boolean) {
     const editorView = RichTextMenu.Instance?.TextView?.EditorView;
     const selected = SelectionManager.Docs().lastElement();
     // prettier-ignore
-    const map: Map<'font'|'fontColor'|'highlight'|'fontSize', { checkResult: () => any; setDoc: () => void;}> = new Map([
+    const map: Map<'font'|'fontColor'|'highlight'|'fontSize'|'alignment', { checkResult: () => any; setDoc: () => void;}> = new Map([
         ['font', {
             checkResult: () => RichTextMenu.Instance?.fontFamily,
             setDoc: () => value && RichTextMenu.Instance.setFontFamily(value),
@@ -139,6 +142,10 @@ ScriptingGlobals.add(function setFontAttr(attr: 'font' | 'fontColor' | 'highligh
             checkResult: () => RichTextMenu.Instance?.fontColor,
             setDoc: () => value && RichTextMenu.Instance.setColor(value),
         }],
+        ['alignment', {
+            checkResult: () => RichTextMenu.Instance.textAlign,
+            setDoc: () => value && editorView?.state ? RichTextMenu.Instance.align(editorView, editorView.dispatch, value):(Doc.UserDoc().textAlign = value),
+        }],
         ['fontSize', {
             checkResult: () => RichTextMenu.Instance?.fontSize.replace('px', ''),
             setDoc: () => {
@@ -157,6 +164,7 @@ ScriptingGlobals.add(function setFontAttr(attr: 'font' | 'fontColor' | 'highligh
 
 type attrname = 'noAutoLink' | 'dictation' | 'bold' | 'italics' | 'underline' | 'left' | 'center' | 'right' | 'bullet' | 'decimal';
 type attrfuncs = [attrname, { checkResult: () => boolean; toggle: () => any }];
+
 ScriptingGlobals.add(function toggleCharStyle(charStyle: attrname, checkResult?: boolean) {
     const textView = RichTextMenu.Instance?.TextView;
     const editorView = textView?.EditorView;
@@ -182,7 +190,10 @@ ScriptingGlobals.add(function toggleCharStyle(charStyle: attrname, checkResult?:
                         toggle: editorView ? RichTextMenu.Instance.toggleUnderline : () => (Doc.UserDoc().textDecoration = Doc.UserDoc().textDecoration === 'underline' ? undefined : 'underline') }]]
 
     const map = new Map(attrs.concat(alignments).concat(listings));
-    if (checkResult) return map.get(charStyle)?.checkResult() ? Colors.MEDIUM_BLUE : 'transparent';
+    if (checkResult) {
+        console.log(charStyle, checkResult, map.get(charStyle)?.checkResult());
+        return map.get(charStyle)?.checkResult();
+    }
     map.get(charStyle)?.toggle();
 });
 
@@ -270,9 +281,9 @@ function setActiveTool(tool: InkTool | GestureUtils.Gestures, keepPrim: boolean,
     if (checkResult) {
         return (Doc.ActiveTool === tool && !GestureOverlay.Instance?.InkShape) || GestureOverlay.Instance?.InkShape === tool
             ? GestureOverlay.Instance?.KeepPrimitiveMode || ![GestureUtils.Gestures.Circle, GestureUtils.Gestures.Line, GestureUtils.Gestures.Rectangle].includes(tool as GestureUtils.Gestures)
-                ? Colors.MEDIUM_BLUE
-                : Colors.MEDIUM_BLUE_ALT
-            : 'transparent';
+                ? true
+                : true
+            : false;
     }
     runInAction(() => {
         if (GestureOverlay.Instance) {
@@ -308,7 +319,7 @@ ScriptingGlobals.add(function setInkProperty(option: 'inkMask' | 'fillColor' | '
     // prettier-ignore
     const map: Map<'inkMask' | 'fillColor' | 'strokeWidth' | 'strokeColor', { checkResult: () => any; setInk: (doc: Doc) => void; setMode: () => void }> = new Map([
         ['inkMask', {
-            checkResult: () => ((selected?.type === DocumentType.INK ? BoolCast(selected.stroke_isInkMask) : ActiveIsInkMask()) ? Colors.MEDIUM_BLUE : 'transparent'),
+            checkResult: () => ((selected?.type === DocumentType.INK ? BoolCast(selected.stroke_isInkMask) : ActiveIsInkMask())),
             setInk: (doc: Doc) => (doc.stroke_isInkMask = !doc.stroke_isInkMask),
             setMode: () => selected?.type !== DocumentType.INK && SetActiveIsInkMask(!ActiveIsInkMask()),
         }],
diff --git a/src/client/views/linking/LinkPopup.scss b/src/client/views/linking/LinkPopup.scss
index b20ad9476..4bfb4b0b9 100644
--- a/src/client/views/linking/LinkPopup.scss
+++ b/src/client/views/linking/LinkPopup.scss
@@ -4,7 +4,6 @@
     top: 0;
     height: 200px;
     width: 200px;
-    position: absolute;
     // padding: 15px;
     border-radius: 3px;
 
@@ -37,8 +36,4 @@
             margin: auto;
         }
     }
-
-    .searchBox-container {
-        background: pink;
-    }
 }
diff --git a/src/client/views/linking/LinkPopup.tsx b/src/client/views/linking/LinkPopup.tsx
index 745efea08..6895c0746 100644
--- a/src/client/views/linking/LinkPopup.tsx
+++ b/src/client/views/linking/LinkPopup.tsx
@@ -14,7 +14,6 @@ import React = require('react');
 import { OpenWhere } from '../nodes/DocumentView';
 
 interface LinkPopupProps {
-    showPopup: boolean;
     linkFrom?: () => Doc | undefined;
     linkCreateAnchor?: () => Doc | undefined;
     linkCreated?: (link: Doc) => void;
@@ -44,10 +43,9 @@ export class LinkPopup extends React.Component<LinkPopupProps> {
     getPHeight = () => 500;
 
     render() {
-        const popupVisibility = this.props.showPopup ? 'block' : 'none';
         const linkDoc = this.props.linkFrom ? this.props.linkFrom : undefined;
         return (
-            <div className="linkPopup-container" style={{ display: popupVisibility }}>
+            <div className="linkPopup-container">
                 {/* <div className="linkPopup-url-container">
                     <input autoComplete="off" type="text" value={this.linkURL} placeholder="Enter URL..." onChange={this.onLinkChange} />
                     <button onPointerDown={e => this.makeLinkToURL(this.linkURL, "add:right")}
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index e954d0484..7e8eef0a5 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -18,7 +18,7 @@ import { SearchBox } from '../search/SearchBox';
 import { DashWebRTCVideo } from '../webcam/DashWebRTCVideo';
 import { YoutubeBox } from './../../apis/youtube/YoutubeBox';
 import { AudioBox } from './AudioBox';
-import { FontIconBox } from './button/FontIconBox';
+import { FontIconBox } from './FontIconBox/FontIconBox';
 import { ColorBox } from './ColorBox';
 import { ComparisonBox } from './ComparisonBox';
 import { DataVizBox } from './DataVizBox/DataVizBox';
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 8a35ca2a4..0b8ea1150 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1111,8 +1111,8 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
         );
         const targetDoc = layout_showTitle?.startsWith('_') ? this.layoutDoc : this.rootDoc;
         const background = StrCast(
-            SharingManager.Instance.users.find(u => u.user.email === this.dataDoc.author)?.sharingDoc.userColor,
-            Doc.UserDoc().layout_showTitle && [DocumentType.RTF, DocumentType.COL].includes(this.rootDoc.type as any) ? StrCast(Doc.SharingDoc().userColor) : 'rgba(0,0,0,0.4)'
+            SharingManager.Instance.users.find(u => u.user.email === this.dataDoc.author)?.sharingDoc.headingColor,
+            Doc.UserDoc().layout_showTitle && [DocumentType.RTF, DocumentType.COL].includes(this.rootDoc.type as any) ? StrCast(Doc.SharingDoc().headingColor) : 'rgba(0,0,0,0.4)'
         );
         const layout_sidebarWidthPercent = +StrCast(this.layoutDoc.layout_sidebarWidthPercent).replace('%', '');
         const titleView = !layout_showTitle ? null : (
diff --git a/src/client/views/nodes/FontIconBox/ButtonInterface.ts b/src/client/views/nodes/FontIconBox/ButtonInterface.ts
new file mode 100644
index 000000000..0aa2ac8e1
--- /dev/null
+++ b/src/client/views/nodes/FontIconBox/ButtonInterface.ts
@@ -0,0 +1,12 @@
+import { Doc } from "../../../../fields/Doc";
+import { IconProp } from "@fortawesome/fontawesome-svg-core";
+import { ButtonType } from "./FontIconBox";
+
+export interface IButtonProps {
+    type: string | ButtonType;
+    rootDoc: Doc;
+    label: any;
+    icon: IconProp;
+    color: string;
+    backgroundColor: string;
+}
\ No newline at end of file
diff --git a/src/client/views/nodes/FontIconBox/FontIconBadge.scss b/src/client/views/nodes/FontIconBox/FontIconBadge.scss
new file mode 100644
index 000000000..78f506e57
--- /dev/null
+++ b/src/client/views/nodes/FontIconBox/FontIconBadge.scss
@@ -0,0 +1,11 @@
+.fontIconBadge {
+    background: red;
+    width: 15px;
+    height: 15px;
+    top: 8px;
+    display: block;
+    position: absolute;
+    right: 5;
+    border-radius: 50%;
+    text-align: center;
+}
\ No newline at end of file
diff --git a/src/client/views/nodes/FontIconBox/FontIconBadge.tsx b/src/client/views/nodes/FontIconBox/FontIconBadge.tsx
new file mode 100644
index 000000000..b50588ce2
--- /dev/null
+++ b/src/client/views/nodes/FontIconBox/FontIconBadge.tsx
@@ -0,0 +1,37 @@
+import { observer } from 'mobx-react';
+import * as React from 'react';
+import './FontIconBadge.scss';
+
+interface FontIconBadgeProps {
+    value: string | undefined;
+}
+
+@observer
+export class FontIconBadge extends React.Component<FontIconBadgeProps> {
+    _notifsRef = React.createRef<HTMLDivElement>();
+
+    // onPointerDown = (e: React.PointerEvent) => {
+    //     setupMoveUpEvents(this, e,
+    //         (e: PointerEvent) => {
+    //             const dragData = new DragManager.DocumentDragData([this.props.collection!]);
+    //             DragManager.StartDocumentDrag([this._notifsRef.current!], dragData, e.x, e.y);
+    //             return true;
+    //         },
+    //         returnFalse, emptyFunction, false);
+    // }
+
+    render() {
+        if (this.props.value === undefined) return null;
+        return (
+            <div className="fontIconBadge-container" ref={this._notifsRef}>
+                <div
+                    className="fontIconBadge"
+                    style={{ display: 'initial' }}
+                    // onPointerDown={this.onPointerDown}
+                >
+                    {this.props.value}
+                </div>
+            </div>
+        );
+    }
+}
diff --git a/src/client/views/nodes/FontIconBox/FontIconBox.scss b/src/client/views/nodes/FontIconBox/FontIconBox.scss
new file mode 100644
index 000000000..9d9fa26b0
--- /dev/null
+++ b/src/client/views/nodes/FontIconBox/FontIconBox.scss
@@ -0,0 +1,438 @@
+@import '../../global/globalCssVariables';
+
+.menuButton {
+    height: 100%;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    font-size: 80%;
+    border-radius: $standard-border-radius;
+    transition: 0.15s;
+
+    .menuButton-wrap {
+        grid-column: 1;
+        justify-content: center;
+        align-items: center;
+        text-align: center;
+    }
+
+    .fontIconBox-label {
+        color: $white;
+        bottom: -1;
+        position: absolute;
+        text-align: center;
+        font-size: 7px;
+        letter-spacing: normal;
+        background-color: inherit;
+        border-radius: 8px;
+        padding: 0;
+        width: 100%;
+        font-family: 'system-ui';
+        text-transform: uppercase;
+        font-weight: bold;
+        transition: 0.15s;
+    }
+
+    .fontIconBox-icon {
+        width: 80%;
+        height: 80%;
+    }
+
+    &.clickBtn,
+    &.clickBtnLabel {
+        cursor: pointer;
+        flex-direction: column;
+
+        svg {
+            width: 50% !important;
+            height: 50%;
+        }
+    }
+
+    &.clickBtnLabel {
+        svg {
+            margin-top: -4px;
+        }
+    }
+
+    &.textBtn {
+        display: grid;
+        /* grid-row: auto; */
+        grid-auto-flow: column;
+        cursor: pointer;
+        width: 100%;
+        justify-content: center;
+        align-items: center;
+        justify-items: center;
+    }
+
+    &.tglBtn,
+    &.tglBtnLabel {
+        cursor: pointer;
+        flex-direction: column;
+
+        &.switch {
+            //TOGGLE
+
+            .switch {
+                position: relative;
+                display: inline-block;
+                width: 100%;
+                height: 25px;
+                margin: 0;
+            }
+
+            .switch input {
+                opacity: 0;
+                width: 0;
+                height: 0;
+            }
+
+            .slider {
+                position: absolute;
+                cursor: pointer;
+                top: 0;
+                left: 0;
+                right: 0;
+                bottom: 0;
+                background-color: lightgrey;
+                -webkit-transition: 0.4s;
+                transition: 0.4s;
+            }
+
+            .slider:before {
+                position: absolute;
+                content: '';
+                height: 21px;
+                width: 21px;
+                left: 2px;
+                bottom: 2px;
+                background-color: $white;
+                -webkit-transition: 0.4s;
+                transition: 0.4s;
+            }
+
+            input:checked + .slider {
+                background-color: $medium-blue;
+            }
+
+            input:focus + .slider {
+                box-shadow: 0 0 1px $medium-blue;
+            }
+
+            input:checked + .slider:before {
+                -webkit-transform: translateX(26px);
+                -ms-transform: translateX(26px);
+                transform: translateX(26px);
+            }
+
+            /* Rounded sliders */
+            .slider.round {
+                border-radius: $standard-border-radius;
+            }
+
+            .slider.round:before {
+                border-radius: $standard-border-radius;
+            }
+        }
+
+        svg {
+            width: 50% !important;
+            height: 50%;
+        }
+
+        &:hover {
+            background-color: rgba(0, 0, 0, 0.3);
+        }
+    }
+
+    &.tglBtnLabel {
+        svg {
+            margin-top: -4px;
+        }
+    }
+
+    &.toolBtn,
+    &.toolBtnLabel {
+        cursor: pointer;
+        width: 100%;
+        border-radius: 100%;
+        flex-direction: column;
+        // margin-top: -4px;
+
+        svg {
+            width: 60% !important;
+            height: 60%;
+        }
+    }
+
+    &.toolBtnLabel {
+        svg {
+            margin-top: -4px;
+        }
+    }
+
+    &.menuBtn {
+        cursor: pointer !important;
+        border-radius: 0px;
+        flex-direction: column;
+
+        svg {
+            width: 45% !important;
+            height: 45%;
+        }
+
+        &:hover {
+            filter: brightness(0.85);
+        }
+    }
+
+    &.colorBtn,
+    &.colorBtnLabel {
+        color: black;
+        cursor: pointer;
+        flex-direction: column;
+        background: transparent;
+
+        .colorButton-color {
+            margin-top: 3px;
+            width: 80%;
+            height: 3px;
+        }
+
+        .menuButton-dropdownBox {
+            position: absolute;
+            width: fit-content;
+            height: fit-content;
+            color: black;
+            top: 100%;
+            left: 0;
+            z-index: 21;
+            background-color: #e3e3e3;
+            box-shadow: 0px 3px 4px rgba(0, 0, 0, 0.3);
+            border-radius: 3px;
+        }
+    }
+
+    &.colorBtnLabel {
+        svg {
+            margin-top: -4px;
+        }
+    }
+
+    &.drpdownList {
+        width: 100%;
+        display: grid;
+        grid-auto-columns: 80px 20px;
+        justify-items: center;
+        font-family: 'Roboto';
+        white-space: nowrap;
+        text-overflow: ellipsis;
+        font-size: 13;
+        font-weight: 600;
+        overflow: hidden;
+        cursor: pointer;
+        background: transparent;
+        align-content: center;
+        align-items: center;
+
+        .menuButton-dropdownList {
+            position: absolute;
+            width: 150px;
+            height: fit-content;
+            top: 100%;
+            z-index: 21;
+            background-color: $white;
+            box-shadow: 0px 3px 4px rgba(0, 0, 0, 0.3);
+            padding: 1px;
+
+            .list-item {
+                color: $black;
+                width: 100%;
+                height: 25px;
+                font-weight: 400;
+                display: flex;
+                justify-content: left;
+                align-items: center;
+                padding-left: 5px;
+            }
+
+            .list-item:hover {
+                background-color: lightgrey;
+            }
+        }
+    }
+
+    &.numBtn {
+        cursor: pointer;
+        background: transparent;
+
+        &.slider {
+            color: $white;
+            cursor: pointer;
+            flex-direction: column;
+            background: transparent;
+
+            .menu-slider {
+                width: 100px;
+            }
+
+            .menuButton-dropdownBox {
+                position: absolute;
+                width: fit-content;
+                height: fit-content;
+                top: 100%;
+                z-index: 21;
+                background-color: #e3e3e3;
+                box-shadow: 0px 3px 4px rgba(0, 0, 0, 0.3);
+                border-radius: $standard-border-radius;
+
+                .menu-slider {
+                    height: 10px;
+                }
+                input[type='range']::-webkit-slider-runnable-track {
+                    background: gray;
+                    height: 3px;
+                }
+
+                input[type='range']::-webkit-slider-thumb {
+                    box-shadow: 1px 1px 1px #000000;
+                    border: 1px solid #000000;
+                    height: 10px;
+                    width: 10px;
+                    border-radius: 5px;
+                    background: #ffffff;
+                    cursor: pointer;
+                    -webkit-appearance: none;
+                    margin-top: -4px;
+                }
+            }
+        }
+
+        .button {
+            width: 25%;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+
+            &.number {
+                width: 50%;
+
+                .button-input {
+                    background: none;
+                    border: none;
+                    text-align: right;
+                    width: 100%;
+                    color: $white;
+                    height: 100%;
+                    text-align: center;
+                }
+
+                .button-input:focus {
+                    outline: none;
+                }
+            }
+        }
+
+        &.list {
+            width: 100%;
+            justify-content: space-around;
+            border: $standard-border;
+
+            .menuButton-dropdownList {
+                position: absolute;
+                width: fit-content;
+                height: fit-content;
+                min-width: 50%;
+                max-height: 50vh;
+                overflow-y: scroll;
+                top: 100%;
+                z-index: 21;
+                background-color: $white;
+                box-shadow: 0px 3px 4px rgba(0, 0, 0, 0.3);
+                padding: 1px;
+
+                .list-item {
+                    color: $black;
+                    width: 100%;
+                    height: 25px;
+                    font-weight: 400;
+                    display: flex;
+                    justify-content: center;
+                    align-items: center;
+                }
+
+                .list-item:hover {
+                    background-color: lightgrey;
+                }
+            }
+        }
+    }
+
+    &.editableText {
+        cursor: text;
+        display: flex;
+        flex-direction: row;
+        gap: 5px;
+        padding-left: 10px;
+        justify-content: flex-start;
+        color: black;
+        background-color: $light-gray;
+        padding: 5px;
+        padding-left: 10px;
+        width: 100%;
+        height: 100%;
+    }
+
+    &.drpDownBtn {
+        cursor: pointer;
+        background: transparent;
+        border: solid 0.5px grey;
+
+        &.true {
+            background: rgba(0, 0, 0, 0.3);
+        }
+
+        .menuButton-dropdownBox {
+            position: absolute;
+            width: 150px;
+            height: 250px;
+            top: 100%;
+            background-color: #e3e3e3;
+            box-shadow: 0px 3px 4px rgba(0, 0, 0, 0.3);
+            border-radius: $standard-border-radius;
+        }
+    }
+
+    .menuButton-dropdown {
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        font-size: 15px;
+        grid-column: 2;
+        border-radius: 0px 7px 7px 0px;
+        width: 13px;
+        height: 100%;
+        right: 0;
+    }
+
+    .menuButton-dropdown-header {
+        width: 100%;
+        font-weight: 300;
+        padding: 5px;
+        overflow: hidden;
+        font-size: 12px;
+        white-space: nowrap;
+        text-overflow: ellipsis;
+    }
+
+    .dropbox-background {
+        width: 200vw;
+        height: 200vh;
+        top: -100vh;
+        z-index: 20;
+        left: -100vw;
+        background: transparent;
+        position: fixed;
+    }
+}
diff --git a/src/client/views/nodes/FontIconBox/FontIconBox.tsx b/src/client/views/nodes/FontIconBox/FontIconBox.tsx
new file mode 100644
index 000000000..2958fa737
--- /dev/null
+++ b/src/client/views/nodes/FontIconBox/FontIconBox.tsx
@@ -0,0 +1,412 @@
+import { IconProp } from '@fortawesome/fontawesome-svg-core';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { Button, ColorPicker, Dropdown, DropdownType, EditableText, IconButton, IListItemProps, NumberDropdown, NumberDropdownType, Popup, Size, 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, StrListCast } from '../../../../fields/Doc';
+import { ScriptField } from '../../../../fields/ScriptField';
+import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
+import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes';
+import { SelectionManager } from '../../../util/SelectionManager';
+import { undoable, UndoManager } from '../../../util/UndoManager';
+import { ContextMenu } from '../../ContextMenu';
+import { DocComponent } from '../../DocComponent';
+import { EditableView } from '../../EditableView';
+import { Colors } from '../../global/globalEnums';
+import { StyleProp } from '../../StyleProvider';
+import { FieldView, FieldViewProps } from '../FieldView';
+import { OpenWhere } from '../DocumentView';
+import { RichTextMenu } from '../formattedText/RichTextMenu';
+import './FontIconBox.scss';
+import { SelectedDocView } from '../../selectedDoc';
+
+export enum ButtonType {
+    TextButton = 'textBtn',
+    MenuButton = 'menuBtn',
+    DropdownList = 'dropdownList',
+    DropdownButton = 'dropdownBtn',
+    ClickButton = 'clickBtn',
+    ToggleButton = 'toggleBtn',
+    ColorButton = 'colorBtn',
+    ToolButton = 'toolBtn',
+    MultiToggleButton = 'multiToggleBtn',
+    NumberSliderButton = 'numSliderBtn',
+    NumberDropdownButton = 'numDropdownBtn',
+    NumberInlineButton = 'numInlineBtn',
+    EditableText = 'editableText',
+}
+
+export interface ButtonProps extends FieldViewProps {
+    type?: ButtonType;
+}
+@observer
+export class FontIconBox extends DocComponent<ButtonProps>() {
+    public static LayoutString(fieldKey: string) {
+        return FieldView.LayoutString(FontIconBox, fieldKey);
+    }
+    @observable noTooltip = false;
+    showTemplate = (): void => {
+        const dragFactory = Cast(this.layoutDoc.dragFactory, Doc, null);
+        dragFactory && this.props.addDocTab(dragFactory, OpenWhere.addRight);
+    };
+    dragAsTemplate = (): void => {
+        this.layoutDoc.onDragStart = ScriptField.MakeFunction('getCopy(this.dragFactory, true)');
+    };
+    useAsPrototype = (): void => {
+        this.layoutDoc.onDragStart = ScriptField.MakeFunction('makeDelegate(this.dragFactory, true)');
+    };
+
+    specificContextMenu = (): void => {
+        if (!Doc.noviceMode) {
+            const cm = ContextMenu.Instance;
+            cm.addItem({ description: 'Show Template', event: this.showTemplate, icon: 'tag' });
+            cm.addItem({ description: 'Use as Render Template', event: this.dragAsTemplate, icon: 'tag' });
+            cm.addItem({ description: 'Use as Prototype', event: this.useAsPrototype, icon: 'tag' });
+        }
+    };
+
+    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));
+    }
+    Icon = (color: string, iconFalse?: boolean) => {
+        let icon;
+        if (iconFalse ) {
+            icon = StrCast(this.dataDoc[this.fieldKey ?? 'iconFalse'] ?? this.dataDoc.icon, 'user') as any;
+            if (icon) return <FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={icon} color={color} />
+            else return null
+        }
+        icon = StrCast(this.dataDoc[this.fieldKey ?? 'icon'] ?? this.dataDoc.icon, 'user') as any;
+        const trailsIcon = () => <img src={`/assets/${'presTrails.png'}`} style={{ width: 30, height: 30, filter: `invert(${color === Colors.DARK_GRAY ? '0%' : '100%'})` }} />;
+        return !icon ? null : icon === 'pres-trail' ? trailsIcon() : <FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={icon} color={color} />;
+    };
+    @computed get dropdown() {
+        return BoolCast(this.rootDoc.dropDownOpen);
+    }
+    @computed get buttonList() {
+        return StrListCast(this.rootDoc.btnList);
+    }
+    @computed get type() {
+        return StrCast(this.rootDoc.btnType);
+    }
+
+    /**
+     * Types of buttons in dash:
+     * - Main menu button (LHS)
+     * - Tool button
+     * - Expandable button (CollectionLinearView)
+     * - Button inside of CollectionLinearView vs. outside of CollectionLinearView
+     * - Action button
+     * - Dropdown button
+     * - Color button
+     * - Dropdown list
+     * - Number button
+     **/
+
+    _batch: UndoManager.Batch | undefined = undefined;
+    /**
+     * Number button
+     */
+    @computed get numberDropdown() {
+        let type: NumberDropdownType;
+        switch(this.type) {
+            case ButtonType.NumberDropdownButton: 
+                type = 'dropdown'
+                break;
+            case ButtonType.NumberInlineButton:
+                type = 'input'
+                break;
+            case ButtonType.NumberSliderButton:
+            default:
+                type = 'slider'
+                break;
+        }
+        const numScript = (value?: number) => ScriptCast(this.rootDoc.script).script.run({ self: this.rootDoc, value, _readOnly_: value === undefined });
+        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>;
+
+        return <NumberDropdown 
+            color={color} 
+            numberDropdownType={type} 
+            showPlusMinus={false} 
+            tooltip={this.label}
+            type={Type.PRIM}
+            min={NumCast(this.rootDoc.numBtnMin, 0)}
+            max={NumCast(this.rootDoc.numBtnMax, 100)}
+            number={checkResult} 
+            setNumber={undoable(value => numScript(value), `${this.rootDoc.title} button set from list`)}
+            fillWidth
+        />
+    }
+
+    /**
+     * Dropdown button
+     */
+    @computed get dropdownButton() {
+        const active: string = StrCast(this.rootDoc.dropDownOpen);
+        const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color);
+        const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor);
+        return (
+            <div
+                className={`menuButton ${this.type} ${active}`}
+                style={{ color: color, backgroundColor: backgroundColor, borderBottomLeftRadius: this.dropdown ? 0 : undefined }}
+                onClick={action(() => {
+                    this.rootDoc.dropDownOpen = !this.rootDoc.dropDownOpen;
+                    this.noTooltip = this.rootDoc.dropDownOpen;
+                    Doc.UnBrushAllDocs();
+                })}>
+                {this.Icon(color)}
+                {!this.label || !FontIconBox.GetShowLabels() ? null : (
+                    <div className="fontIconBox-label" style={{ color: color, backgroundColor: backgroundColor }}>
+                        {' '}
+                        {this.label}{' '}
+                    </div>
+                )}
+                <div className="menuButton-dropdown" style={{ borderBottomRightRadius: this.dropdown ? 0 : undefined }}>
+                    <FontAwesomeIcon icon={'caret-down'} color={color} size="sm" />
+                </div>
+                {this.rootDoc.dropDownOpen ? <div className="menuButton-dropdownBox">{/* DROPDOWN BOX CONTENTS */}</div> : null}
+            </div>
+        );
+    }
+
+    /**
+     * Dropdown list
+     */
+    @computed get dropdownListButton() {
+        const active: string = StrCast(this.rootDoc.dropDownOpen);
+        const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color);
+        const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor);
+
+        const script = ScriptCast(this.rootDoc.script);
+
+        let noviceList: string[] = [];
+        let text: string | undefined;
+        let dropdown = true;
+        let getStyle: (val: string) => any = () => {};
+        let icon: IconProp = 'caret-down';
+        let isViewDropdown: boolean = script?.script.originalScript.startsWith('setView')
+        try {
+            if (isViewDropdown) {
+                const selectedDocs: Doc[] = SelectionManager.Docs();
+                const selected = SelectionManager.Docs().lastElement();
+                console.log('selected')
+                if (selected) {
+                    if (StrCast(selected.type) === DocumentType.COL) {
+                        text = StrCast(selected._type_collection);
+                    } else {
+                        console.log("doc selected", selected.title);
+                        dropdown = false;
+                        if (selectedDocs.length > 1) {
+                            text = selectedDocs.length + " documents selected"
+                        } else {
+                            text = selected.type === DocumentType.RTF ? 'Text' : StrCast(selected.type);
+                            icon = Doc.toIcon(selected);
+                        }
+                        return <Popup
+                            icon={<FontAwesomeIcon size={'1x'} icon={icon} />}
+                            text={text}
+                            type={Type.TERT}
+                            color={color}
+                            popup={<SelectedDocView selectedDocs={selectedDocs}/>}
+                            fillWidth
+                        />
+                    }
+                } else {
+                    dropdown = false;
+                    return <Button 
+                        text={`None Selected`} 
+                        type={Type.TERT}
+                        color={color}
+                        fillWidth
+                        inactive
+                    />
+                }
+                noviceList = [CollectionViewType.Freeform, CollectionViewType.Schema, CollectionViewType.Stacking, CollectionViewType.NoteTaking];
+            } else { 
+                text = StrCast((RichTextMenu.Instance?.TextView?.EditorView ? RichTextMenu.Instance : Doc.UserDoc()).fontFamily);
+                getStyle = (val: string) => { return { fontFamily: val } }
+            }
+        } catch (e) {
+            console.log(e);
+        }
+
+        console.log("current item: ", text);
+
+        // Get items to place into the list
+        const list: IListItemProps[] = this.buttonList
+            .filter(value => !Doc.noviceMode || !noviceList.length || noviceList.includes(value))
+            .map(value => (
+                {
+                    text: value.charAt(0).toUpperCase() + value.slice(1),
+                    val: value,
+                    style: getStyle(value),
+                    onClick: undoable(() => script.script.run({ self: this.rootDoc, value }), value)
+                    // shortcut: '#',
+                }
+            ));
+
+
+        return (
+            <Dropdown 
+                selectedVal={text}
+                setSelectedVal={undoable((val) => script.script.run({ self: this.rootDoc, val }), `dropdown select ${this.label}`)}
+                color={color} 
+                type={isViewDropdown ? Type.TERT : Type.PRIM} 
+                dropdownType={DropdownType.SELECT} 
+                items={list}
+                tooltip={this.label}
+                fillWidth
+            />
+        )
+    }
+
+
+    @computed get colorScript() {
+        return ScriptCast(this.rootDoc.script);
+    }
+
+    /**
+     * Color button
+     */
+    @computed get colorButton() {
+        const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color);
+        const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor);
+        const curColor = this.colorScript?.script.run({ self: this.rootDoc, value: undefined, _readOnly_: true }).result ?? 'transparent';
+        const tooltip: string = StrCast(this.rootDoc.toolTip);
+
+        return (
+            <ColorPicker 
+                setSelectedColor={(value) => {
+                    const s = this.colorScript;
+                    s && undoable(() => s.script.run({ self: this.rootDoc, value: value, _readOnly_: false }).result, `Set ${tooltip} to ${value}`)();
+                }}
+                selectedColor={curColor}
+                type={Type.PRIM}
+                color={color}
+                icon={this.Icon(color)!}
+                tooltip={tooltip}
+                label={this.label}
+            />
+        )
+    }
+
+    @computed get toggleButton() {
+        // Determine the type of toggle button
+        const buttonText: string = StrCast(this.rootDoc.buttonText);
+        const tooltip: string = StrCast(this.rootDoc.toolTip);
+
+        const script = ScriptCast(this.rootDoc.onClick);
+        const toggleStatus = script ? script.script.run({ self: this.rootDoc, value: undefined, _readOnly_: true }).result : false;
+        // Colors
+        const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color);
+        const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor);
+
+        console.log(tooltip, toggleStatus);
+        return (
+            <Toggle tooltip={`Toggle ${tooltip}`} toggleType={ToggleType.BUTTON} type={Type.PRIM} toggleStatus={toggleStatus} text={buttonText} color={color} icon={this.Icon(color)!} label={this.label}/>
+        )
+    }
+
+    /**
+     * Default
+     */
+    @computed get defaultButton() {
+        const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color);
+        const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor);
+        const tooltip: string = StrCast(this.rootDoc.toolTip);
+
+        return (
+            <IconButton tooltip={tooltip} icon={this.Icon(color)!} label={this.label}/>
+        )
+    }
+
+    @computed get editableText() {
+        // Script for running the toggle
+        const script = ScriptCast(this.rootDoc.script);
+        // Function to run the script
+        const checkResult = script?.script.run({ value: '', _readOnly_: true }).result;
+
+        const setValue = (value: string, shiftDown?: boolean): boolean => script?.script.run({ value, _readOnly_: false }).result;
+        
+        return <EditableText 
+            editing={false} setEditing={(editing: boolean) => {}}            
+        />
+        
+        return (
+            <div className="menuButton editableText">
+                <FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={'lock'} />
+                <div style={{ width: 'calc(100% - .875em)', paddingLeft: '4px' }}>
+                    <EditableView GetValue={() => script?.script.run({ value: '', _readOnly_: true }).result} SetValue={setValue} oneLine={true} contents={checkResult} />
+                </div>
+            </div>
+        );
+    }
+
+    render() {
+        // determine dash button metadata
+        const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color);
+        const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor);
+        const tooltip: string = StrCast(this.rootDoc.toolTip);
+
+        // TODO:glr Add label of button type
+        let button: JSX.Element = this.defaultButton;
+        // prettier-ignore
+        switch (this.type) {
+            case ButtonType.EditableText: 
+                button = this.editableText;
+                break;
+            case ButtonType.DropdownList:
+                button = this.dropdownListButton;
+                break;
+            case ButtonType.ColorButton: 
+                button = this.colorButton; 
+                break;
+            case ButtonType.NumberDropdownButton: 
+            case ButtonType.NumberInlineButton:
+            case ButtonType.NumberSliderButton: 
+                button = this.numberDropdown; 
+                break;
+            case ButtonType.DropdownButton: 
+                button = this.dropdownButton; 
+                break;
+            case ButtonType.ToggleButton: button = this.toggleButton; break;
+            case ButtonType.TextButton: 
+                // Script for checking the outcome of the toggle
+                const script = ScriptCast(this.rootDoc.script);
+                const checkResult = script?.script.run({ _readOnly_: true }).result;
+                button = (
+                    <Button tooltip={tooltip} color={checkResult ?? backgroundColor} icon={this.Icon(color)!} text={StrCast(this.rootDoc.buttonText)} label={this.label}/>
+                );
+                break;
+            case ButtonType.ClickButton:
+            case ButtonType.ToolButton: 
+                button = (
+                    <IconButton tooltip={tooltip} color={color} icon={this.Icon(color)!} label={this.label}/>
+                );
+                break;
+            case ButtonType.MenuButton: button = (
+                    <IconButton tooltip={tooltip} tooltipPlacement='right' size={Size.LARGE} color={color} icon={this.Icon(color)!} label={this.label}/>
+                );
+                break;
+        }
+
+        return button;
+    }
+}
diff --git a/src/client/views/nodes/button/FontIconBox.scss b/src/client/views/nodes/button/FontIconBox.scss
deleted file mode 100644
index 9d9fa26b0..000000000
--- a/src/client/views/nodes/button/FontIconBox.scss
+++ /dev/null
@@ -1,438 +0,0 @@
-@import '../../global/globalCssVariables';
-
-.menuButton {
-    height: 100%;
-    display: flex;
-    justify-content: center;
-    align-items: center;
-    font-size: 80%;
-    border-radius: $standard-border-radius;
-    transition: 0.15s;
-
-    .menuButton-wrap {
-        grid-column: 1;
-        justify-content: center;
-        align-items: center;
-        text-align: center;
-    }
-
-    .fontIconBox-label {
-        color: $white;
-        bottom: -1;
-        position: absolute;
-        text-align: center;
-        font-size: 7px;
-        letter-spacing: normal;
-        background-color: inherit;
-        border-radius: 8px;
-        padding: 0;
-        width: 100%;
-        font-family: 'system-ui';
-        text-transform: uppercase;
-        font-weight: bold;
-        transition: 0.15s;
-    }
-
-    .fontIconBox-icon {
-        width: 80%;
-        height: 80%;
-    }
-
-    &.clickBtn,
-    &.clickBtnLabel {
-        cursor: pointer;
-        flex-direction: column;
-
-        svg {
-            width: 50% !important;
-            height: 50%;
-        }
-    }
-
-    &.clickBtnLabel {
-        svg {
-            margin-top: -4px;
-        }
-    }
-
-    &.textBtn {
-        display: grid;
-        /* grid-row: auto; */
-        grid-auto-flow: column;
-        cursor: pointer;
-        width: 100%;
-        justify-content: center;
-        align-items: center;
-        justify-items: center;
-    }
-
-    &.tglBtn,
-    &.tglBtnLabel {
-        cursor: pointer;
-        flex-direction: column;
-
-        &.switch {
-            //TOGGLE
-
-            .switch {
-                position: relative;
-                display: inline-block;
-                width: 100%;
-                height: 25px;
-                margin: 0;
-            }
-
-            .switch input {
-                opacity: 0;
-                width: 0;
-                height: 0;
-            }
-
-            .slider {
-                position: absolute;
-                cursor: pointer;
-                top: 0;
-                left: 0;
-                right: 0;
-                bottom: 0;
-                background-color: lightgrey;
-                -webkit-transition: 0.4s;
-                transition: 0.4s;
-            }
-
-            .slider:before {
-                position: absolute;
-                content: '';
-                height: 21px;
-                width: 21px;
-                left: 2px;
-                bottom: 2px;
-                background-color: $white;
-                -webkit-transition: 0.4s;
-                transition: 0.4s;
-            }
-
-            input:checked + .slider {
-                background-color: $medium-blue;
-            }
-
-            input:focus + .slider {
-                box-shadow: 0 0 1px $medium-blue;
-            }
-
-            input:checked + .slider:before {
-                -webkit-transform: translateX(26px);
-                -ms-transform: translateX(26px);
-                transform: translateX(26px);
-            }
-
-            /* Rounded sliders */
-            .slider.round {
-                border-radius: $standard-border-radius;
-            }
-
-            .slider.round:before {
-                border-radius: $standard-border-radius;
-            }
-        }
-
-        svg {
-            width: 50% !important;
-            height: 50%;
-        }
-
-        &:hover {
-            background-color: rgba(0, 0, 0, 0.3);
-        }
-    }
-
-    &.tglBtnLabel {
-        svg {
-            margin-top: -4px;
-        }
-    }
-
-    &.toolBtn,
-    &.toolBtnLabel {
-        cursor: pointer;
-        width: 100%;
-        border-radius: 100%;
-        flex-direction: column;
-        // margin-top: -4px;
-
-        svg {
-            width: 60% !important;
-            height: 60%;
-        }
-    }
-
-    &.toolBtnLabel {
-        svg {
-            margin-top: -4px;
-        }
-    }
-
-    &.menuBtn {
-        cursor: pointer !important;
-        border-radius: 0px;
-        flex-direction: column;
-
-        svg {
-            width: 45% !important;
-            height: 45%;
-        }
-
-        &:hover {
-            filter: brightness(0.85);
-        }
-    }
-
-    &.colorBtn,
-    &.colorBtnLabel {
-        color: black;
-        cursor: pointer;
-        flex-direction: column;
-        background: transparent;
-
-        .colorButton-color {
-            margin-top: 3px;
-            width: 80%;
-            height: 3px;
-        }
-
-        .menuButton-dropdownBox {
-            position: absolute;
-            width: fit-content;
-            height: fit-content;
-            color: black;
-            top: 100%;
-            left: 0;
-            z-index: 21;
-            background-color: #e3e3e3;
-            box-shadow: 0px 3px 4px rgba(0, 0, 0, 0.3);
-            border-radius: 3px;
-        }
-    }
-
-    &.colorBtnLabel {
-        svg {
-            margin-top: -4px;
-        }
-    }
-
-    &.drpdownList {
-        width: 100%;
-        display: grid;
-        grid-auto-columns: 80px 20px;
-        justify-items: center;
-        font-family: 'Roboto';
-        white-space: nowrap;
-        text-overflow: ellipsis;
-        font-size: 13;
-        font-weight: 600;
-        overflow: hidden;
-        cursor: pointer;
-        background: transparent;
-        align-content: center;
-        align-items: center;
-
-        .menuButton-dropdownList {
-            position: absolute;
-            width: 150px;
-            height: fit-content;
-            top: 100%;
-            z-index: 21;
-            background-color: $white;
-            box-shadow: 0px 3px 4px rgba(0, 0, 0, 0.3);
-            padding: 1px;
-
-            .list-item {
-                color: $black;
-                width: 100%;
-                height: 25px;
-                font-weight: 400;
-                display: flex;
-                justify-content: left;
-                align-items: center;
-                padding-left: 5px;
-            }
-
-            .list-item:hover {
-                background-color: lightgrey;
-            }
-        }
-    }
-
-    &.numBtn {
-        cursor: pointer;
-        background: transparent;
-
-        &.slider {
-            color: $white;
-            cursor: pointer;
-            flex-direction: column;
-            background: transparent;
-
-            .menu-slider {
-                width: 100px;
-            }
-
-            .menuButton-dropdownBox {
-                position: absolute;
-                width: fit-content;
-                height: fit-content;
-                top: 100%;
-                z-index: 21;
-                background-color: #e3e3e3;
-                box-shadow: 0px 3px 4px rgba(0, 0, 0, 0.3);
-                border-radius: $standard-border-radius;
-
-                .menu-slider {
-                    height: 10px;
-                }
-                input[type='range']::-webkit-slider-runnable-track {
-                    background: gray;
-                    height: 3px;
-                }
-
-                input[type='range']::-webkit-slider-thumb {
-                    box-shadow: 1px 1px 1px #000000;
-                    border: 1px solid #000000;
-                    height: 10px;
-                    width: 10px;
-                    border-radius: 5px;
-                    background: #ffffff;
-                    cursor: pointer;
-                    -webkit-appearance: none;
-                    margin-top: -4px;
-                }
-            }
-        }
-
-        .button {
-            width: 25%;
-            display: flex;
-            align-items: center;
-            justify-content: center;
-
-            &.number {
-                width: 50%;
-
-                .button-input {
-                    background: none;
-                    border: none;
-                    text-align: right;
-                    width: 100%;
-                    color: $white;
-                    height: 100%;
-                    text-align: center;
-                }
-
-                .button-input:focus {
-                    outline: none;
-                }
-            }
-        }
-
-        &.list {
-            width: 100%;
-            justify-content: space-around;
-            border: $standard-border;
-
-            .menuButton-dropdownList {
-                position: absolute;
-                width: fit-content;
-                height: fit-content;
-                min-width: 50%;
-                max-height: 50vh;
-                overflow-y: scroll;
-                top: 100%;
-                z-index: 21;
-                background-color: $white;
-                box-shadow: 0px 3px 4px rgba(0, 0, 0, 0.3);
-                padding: 1px;
-
-                .list-item {
-                    color: $black;
-                    width: 100%;
-                    height: 25px;
-                    font-weight: 400;
-                    display: flex;
-                    justify-content: center;
-                    align-items: center;
-                }
-
-                .list-item:hover {
-                    background-color: lightgrey;
-                }
-            }
-        }
-    }
-
-    &.editableText {
-        cursor: text;
-        display: flex;
-        flex-direction: row;
-        gap: 5px;
-        padding-left: 10px;
-        justify-content: flex-start;
-        color: black;
-        background-color: $light-gray;
-        padding: 5px;
-        padding-left: 10px;
-        width: 100%;
-        height: 100%;
-    }
-
-    &.drpDownBtn {
-        cursor: pointer;
-        background: transparent;
-        border: solid 0.5px grey;
-
-        &.true {
-            background: rgba(0, 0, 0, 0.3);
-        }
-
-        .menuButton-dropdownBox {
-            position: absolute;
-            width: 150px;
-            height: 250px;
-            top: 100%;
-            background-color: #e3e3e3;
-            box-shadow: 0px 3px 4px rgba(0, 0, 0, 0.3);
-            border-radius: $standard-border-radius;
-        }
-    }
-
-    .menuButton-dropdown {
-        display: flex;
-        justify-content: center;
-        align-items: center;
-        font-size: 15px;
-        grid-column: 2;
-        border-radius: 0px 7px 7px 0px;
-        width: 13px;
-        height: 100%;
-        right: 0;
-    }
-
-    .menuButton-dropdown-header {
-        width: 100%;
-        font-weight: 300;
-        padding: 5px;
-        overflow: hidden;
-        font-size: 12px;
-        white-space: nowrap;
-        text-overflow: ellipsis;
-    }
-
-    .dropbox-background {
-        width: 200vw;
-        height: 200vh;
-        top: -100vh;
-        z-index: 20;
-        left: -100vw;
-        background: transparent;
-        position: fixed;
-    }
-}
diff --git a/src/client/views/nodes/button/FontIconBox.tsx b/src/client/views/nodes/button/FontIconBox.tsx
deleted file mode 100644
index e31407f4b..000000000
--- a/src/client/views/nodes/button/FontIconBox.tsx
+++ /dev/null
@@ -1,385 +0,0 @@
-import { IconProp } from '@fortawesome/fontawesome-svg-core';
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { Button, ColorPicker, Dropdown, DropdownType, EditableText, IconButton, IListItemProps, NumberDropdown, NumberDropdownType, Size, Toggle, ToggleType, Type } from 'browndash-components';
-import { action, computed, observable } from 'mobx';
-import { observer } from 'mobx-react';
-import * as React from 'react';
-import { Doc, StrListCast } from '../../../../fields/Doc';
-import { ScriptField } from '../../../../fields/ScriptField';
-import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
-import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes';
-import { SelectionManager } from '../../../util/SelectionManager';
-import { undoable, UndoManager } from '../../../util/UndoManager';
-import { ContextMenu } from '../../ContextMenu';
-import { DocComponent } from '../../DocComponent';
-import { EditableView } from '../../EditableView';
-import { Colors } from '../../global/globalEnums';
-import { StyleProp } from '../../StyleProvider';
-import { FieldView, FieldViewProps } from '.././FieldView';
-import { OpenWhere } from '../DocumentView';
-import { RichTextMenu } from '../formattedText/RichTextMenu';
-import './FontIconBox.scss';
-
-export enum ButtonType {
-    TextButton = 'textBtn',
-    MenuButton = 'menuBtn',
-    DropdownList = 'drpdownList',
-    DropdownButton = 'drpdownBtn',
-    ClickButton = 'clickBtn',
-    DoubleButton = 'dblBtn',
-    ToggleButton = 'tglBtn',
-    ColorButton = 'colorBtn',
-    ToolButton = 'toolBtn',
-    NumberSliderButton = 'numSliderBtn',
-    NumberDropdownButton = 'numDropdownBtn',
-    NumberInlineButton = 'numInlineBtn',
-    EditableText = 'editableText',
-}
-
-export interface ButtonProps extends FieldViewProps {
-    type?: ButtonType;
-}
-@observer
-export class FontIconBox extends DocComponent<ButtonProps>() {
-    public static LayoutString(fieldKey: string) {
-        return FieldView.LayoutString(FontIconBox, fieldKey);
-    }
-    @observable noTooltip = false;
-    showTemplate = (): void => {
-        const dragFactory = Cast(this.layoutDoc.dragFactory, Doc, null);
-        dragFactory && this.props.addDocTab(dragFactory, OpenWhere.addRight);
-    };
-    dragAsTemplate = (): void => {
-        this.layoutDoc.onDragStart = ScriptField.MakeFunction('getCopy(this.dragFactory, true)');
-    };
-    useAsPrototype = (): void => {
-        this.layoutDoc.onDragStart = ScriptField.MakeFunction('makeDelegate(this.dragFactory, true)');
-    };
-
-    specificContextMenu = (): void => {
-        if (!Doc.noviceMode) {
-            const cm = ContextMenu.Instance;
-            cm.addItem({ description: 'Show Template', event: this.showTemplate, icon: 'tag' });
-            cm.addItem({ description: 'Use as Render Template', event: this.dragAsTemplate, icon: 'tag' });
-            cm.addItem({ description: 'Use as Prototype', event: this.useAsPrototype, icon: 'tag' });
-        }
-    };
-
-    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));
-    }
-    Icon = (color: string, iconFalse?: boolean) => {
-        let icon;
-        if (iconFalse ) {
-            icon = StrCast(this.dataDoc[this.fieldKey ?? 'iconFalse'] ?? this.dataDoc.icon, 'user') as any;
-            if (icon) return <FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={icon} color={color} />
-            else return null
-        }
-        icon = StrCast(this.dataDoc[this.fieldKey ?? 'icon'] ?? this.dataDoc.icon, 'user') as any;
-        const trailsIcon = () => <img src={`/assets/${'presTrails.png'}`} style={{ width: 30, height: 30, filter: `invert(${color === Colors.DARK_GRAY ? '0%' : '100%'})` }} />;
-        return !icon ? null : icon === 'pres-trail' ? trailsIcon() : <FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={icon} color={color} />;
-    };
-    @computed get dropdown() {
-        return BoolCast(this.rootDoc.dropDownOpen);
-    }
-    @computed get buttonList() {
-        return StrListCast(this.rootDoc.btnList);
-    }
-    @computed get type() {
-        return StrCast(this.rootDoc.btnType);
-    }
-
-    /**
-     * Types of buttons in dash:
-     * - Main menu button (LHS)
-     * - Tool button
-     * - Expandable button (CollectionLinearView)
-     * - Button inside of CollectionLinearView vs. outside of CollectionLinearView
-     * - Action button
-     * - Dropdown button
-     * - Color button
-     * - Dropdown list
-     * - Number button
-     **/
-
-    _batch: UndoManager.Batch | undefined = undefined;
-    /**
-     * Number button
-     */
-    @computed get numberDropdown() {
-        let type: NumberDropdownType;
-        switch(this.type) {
-            case ButtonType.NumberDropdownButton: 
-                type = 'dropdown'
-                break;
-            case ButtonType.NumberInlineButton:
-                type = 'input'
-                break;
-            case ButtonType.NumberSliderButton:
-            default:
-                type = 'slider'
-                break;
-        }
-        const numScript = (value?: number) => ScriptCast(this.rootDoc.script).script.run({ self: this.rootDoc, value, _readOnly_: value === undefined });
-        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>;
-
-        return <NumberDropdown 
-            color={color} 
-            numberDropdownType={type} 
-            showPlusMinus={false} 
-            min={NumCast(this.rootDoc.numBtnMin, 0)}
-            max={NumCast(this.rootDoc.numBtnMax, 100)}
-            number={checkResult} 
-            setNumber={undoable(value => numScript(value), `${this.rootDoc.title} button set from list`)}
-        />
-    }
-
-    /**
-     * Dropdown button
-     */
-    @computed get dropdownButton() {
-        const active: string = StrCast(this.rootDoc.dropDownOpen);
-        const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color);
-        const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor);
-        return (
-            <div
-                className={`menuButton ${this.type} ${active}`}
-                style={{ color: color, backgroundColor: backgroundColor, borderBottomLeftRadius: this.dropdown ? 0 : undefined }}
-                onClick={action(() => {
-                    this.rootDoc.dropDownOpen = !this.rootDoc.dropDownOpen;
-                    this.noTooltip = this.rootDoc.dropDownOpen;
-                    Doc.UnBrushAllDocs();
-                })}>
-                {this.Icon(color)}
-                {!this.label || !FontIconBox.GetShowLabels() ? null : (
-                    <div className="fontIconBox-label" style={{ color: color, backgroundColor: backgroundColor }}>
-                        {' '}
-                        {this.label}{' '}
-                    </div>
-                )}
-                <div className="menuButton-dropdown" style={{ borderBottomRightRadius: this.dropdown ? 0 : undefined }}>
-                    <FontAwesomeIcon icon={'caret-down'} color={color} size="sm" />
-                </div>
-                {this.rootDoc.dropDownOpen ? <div className="menuButton-dropdownBox">{/* DROPDOWN BOX CONTENTS */}</div> : null}
-            </div>
-        );
-    }
-
-    /**
-     * Dropdown list
-     */
-    @computed get dropdownListButton() {
-        const active: string = StrCast(this.rootDoc.dropDownOpen);
-        const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color);
-        const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor);
-
-        const script = ScriptCast(this.rootDoc.script);
-
-        let noviceList: string[] = [];
-        let text: string | undefined;
-        let dropdown = true;
-        let icon: IconProp = 'caret-down';
-        try {
-            if (script?.script.originalScript.startsWith('setView')) {
-                const selected = SelectionManager.Docs().lastElement();
-                console.log('selected')
-                if (selected) {
-                    if (StrCast(selected.type) === DocumentType.COL) {
-                        text = StrCast(selected._type_collection);
-                    } else {
-                        console.log("doc selected", selected.title)
-                        dropdown = false;
-                        text = selected.type === DocumentType.RTF ? 'Text' : StrCast(selected.type);
-                        icon = Doc.toIcon(selected);
-                        return <div>Hi!</div>
-                    }
-                } else {
-                    dropdown = false;
-                    icon = 'globe-asia';
-                    text = 'User Default';
-                    return <div>Hi!</div>
-                }
-                noviceList = [CollectionViewType.Freeform, CollectionViewType.Schema, CollectionViewType.Stacking, CollectionViewType.NoteTaking];
-            } else text = StrCast((RichTextMenu.Instance?.TextView?.EditorView ? RichTextMenu.Instance : Doc.UserDoc()).fontFamily);
-        } catch (e) {
-            console.log(e);
-        }
-
-        console.log("current item: ", text);
-
-        // Get items to place into the list
-        const list: IListItemProps[] = this.buttonList
-            .filter(value => !Doc.noviceMode || !noviceList.length || noviceList.includes(value))
-            .map(value => (
-                {
-                    text: value,
-                    val: value,
-                    style: { fontFamily: value },
-                    onClick: undoable(() => script.script.run({ self: this.rootDoc, value }), value)
-                    // shortcut: '#',
-                }
-            ));
-
-
-        return (
-            <Dropdown 
-                selectedVal={text}
-                setSelectedVal={undoable((val) => script.script.run({ self: this.rootDoc, val }), `dropdown select ${this.label}`)}
-                color={Colors.WHITE} 
-                type={Type.PRIM} 
-                dropdownType={DropdownType.SELECT} 
-                items={list}
-                tooltip={this.label}
-            />
-        )
-    }
-
-
-    @computed get colorScript() {
-        return ScriptCast(this.rootDoc.script);
-    }
-
-    /**
-     * Color button
-     */
-    @computed get colorButton() {
-        const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color);
-        const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor);
-        const curColor = this.colorScript?.script.run({ self: this.rootDoc, value: undefined, _readOnly_: true }).result ?? 'transparent';
-        const tooltip: string = StrCast(this.rootDoc.toolTip);
-
-        return (
-            <ColorPicker 
-                setSelectedColor={(value) => {
-                    const s = this.colorScript;
-                    s && undoable(() => s.script.run({ self: this.rootDoc, value: value, _readOnly_: false }).result, `Set ${tooltip} to ${value}`)();
-                }}
-                selectedColor={curColor}
-                type={Type.PRIM}
-                color={color}
-                icon={this.Icon(color)!}
-                tooltip={tooltip}
-                label={this.label}
-            />
-        )
-    }
-
-    @computed get toggleButton() {
-        // Determine the type of toggle button
-        const switchToggle: boolean = BoolCast(this.rootDoc.switchToggle);
-        const buttonText: string = StrCast(this.rootDoc.buttonText);
-        const tooltip: string = StrCast(this.rootDoc.toolTip);
-        
-        // Colors
-        const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color);
-        const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor);
-
-        console.log(buttonText, tooltip);
-        return (
-            <Toggle tooltip={`Toggle + ${tooltip}`} toggleType={ToggleType.BUTTON} type={Type.PRIM} toggleStatus={switchToggle} text={buttonText} color={color} icon={this.Icon(color)!} label={this.label}/>
-        )
-    }
-
-    /**
-     * Default
-     */
-    @computed get defaultButton() {
-        const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color);
-        const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor);
-        const tooltip: string = StrCast(this.rootDoc.toolTip);
-
-        return (
-            <IconButton tooltip={tooltip} icon={this.Icon(color)!} label={this.label}/>
-        )
-    }
-
-    @computed get editableText() {
-        // Script for running the toggle
-        const script = ScriptCast(this.rootDoc.script);
-        // Function to run the script
-        const checkResult = script?.script.run({ value: '', _readOnly_: true }).result;
-
-        const setValue = (value: string, shiftDown?: boolean): boolean => script?.script.run({ value, _readOnly_: false }).result;
-        
-        return <EditableText 
-            editing={false} onEdit={() => {}} setEditing={(editing: boolean) => {}}            
-        />
-        
-        return (
-            <div className="menuButton editableText">
-                <FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={'lock'} />
-                <div style={{ width: 'calc(100% - .875em)', paddingLeft: '4px' }}>
-                    <EditableView GetValue={() => script?.script.run({ value: '', _readOnly_: true }).result} SetValue={setValue} oneLine={true} contents={checkResult} />
-                </div>
-            </div>
-        );
-    }
-
-    render() {
-        // determine dash button metadata
-        const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color);
-        const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor);
-        const tooltip: string = StrCast(this.rootDoc.toolTip);
-
-        // TODO:glr Add label of button type
-        let button: JSX.Element = this.defaultButton;
-        // prettier-ignore
-        switch (this.type) {
-            case ButtonType.EditableText: 
-                button = this.editableText;
-                break;
-            case ButtonType.DropdownList:
-                button = this.dropdownListButton;
-                break;
-            case ButtonType.ColorButton: 
-                button = this.colorButton; 
-                break;
-            case ButtonType.NumberDropdownButton: 
-            case ButtonType.NumberInlineButton:
-            case ButtonType.NumberSliderButton: 
-                button = this.numberDropdown; 
-                break;
-            case ButtonType.DropdownButton: 
-                button = this.dropdownButton; 
-                break;
-            case ButtonType.ToggleButton: button = this.toggleButton; break;
-            case ButtonType.TextButton: 
-                // Script for checking the outcome of the toggle
-                const script = ScriptCast(this.rootDoc.script);
-                const checkResult = script?.script.run({ _readOnly_: true }).result;
-                button = (
-                    <Button tooltip={tooltip} color={checkResult ?? backgroundColor} icon={this.Icon(color)!} text={StrCast(this.rootDoc.buttonText)} label={this.label}/>
-                );
-                break;
-            case ButtonType.ClickButton:
-            case ButtonType.ToolButton: 
-                button = (
-                    <IconButton tooltip={tooltip} color={color} icon={this.Icon(color)!} label={this.label}/>
-                );
-                break;
-            case ButtonType.MenuButton: button = (
-                    <IconButton tooltip={tooltip} tooltipPlacement='right' size={Size.LARGE} color={color} icon={this.Icon(color)!} label={this.label}/>
-                );
-                break;
-        }
-
-        return button;
-    }
-}
diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx
index 5480600b0..64ea4f52c 100644
--- a/src/client/views/pdf/AnchorMenu.tsx
+++ b/src/client/views/pdf/AnchorMenu.tsx
@@ -15,6 +15,8 @@ import { GPTPopup, GPTPopupMode } from './GPTPopup/GPTPopup';
 import { LightboxView } from '../LightboxView';
 import { EditorView } from 'prosemirror-view';
 import './AnchorMenu.scss';
+import { ColorPicker, Group, IconButton, Popup, Size, Type } from 'browndash-components';
+import { StrCast } from '../../../fields/Types';
 
 @observer
 export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
@@ -42,7 +44,6 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
     ];
 
     @observable private highlightColor: string = 'rgba(245, 230, 95, 0.616)';
-    @observable private _showLinkPopup: boolean = false;
 
     @observable public Status: 'marquee' | 'annotation' | '' = '';
 
@@ -131,7 +132,6 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
             () => this._opacity,
             opacity => {
                 if (!opacity) {
-                    this._showLinkPopup = false;
                     this.setGPTPopupVis(false);
                     this.setGPTPopupText('');
                 }
@@ -141,7 +141,6 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
         this._disposer = reaction(
             () => SelectionManager.Views().slice(),
             selected => {
-                this._showLinkPopup = false;
                 this.setGPTPopupVis(false);
                 this.setGPTPopupText('');
                 AnchorMenu.Instance.fadeOut(true);
@@ -253,49 +252,25 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
         AnchorMenu.Instance.fadeOut(true);
     };
 
-    @action
-    toggleLinkPopup = (e: React.MouseEvent) => {
-        //ignore the potential null type error because this method cannot be called unless the user selects text and clicks the link button
-        //change popup visibility field to visible
-        this._showLinkPopup = !this._showLinkPopup;
-    };
-
     @computed get highlighter() {
-        const button = (
-            <button className="antimodeMenu-button anchor-color-preview-button" title="" key="highlighter-button" onClick={this.highlightClicked}>
-                <div className="anchor-color-preview">
-                    <FontAwesomeIcon icon="highlighter" size="lg" style={{ transition: 'transform 0.1s', transform: 'rotate(-45deg)' }} />
-                    <div className="color-preview" style={{ backgroundColor: this.highlightColor }}></div>
-                </div>
-            </button>
-        );
-
-        const dropdownContent = (
-            <div className="dropdown">
-                <p>Change highlighter color:</p>
-                <div className="color-wrapper">
-                    {this._palette.map(color => {
-                        if (color) {
-                            return this.highlightColor === color ? (
-                                <button className="color-button active" key={`active ${color}`} style={{ backgroundColor: color }} onPointerDown={e => this.changeHighlightColor(color, e)}></button>
-                            ) : (
-                                <button className="color-button" key={`inactive ${color}`} style={{ backgroundColor: color }} onPointerDown={e => this.changeHighlightColor(color, e)}></button>
-                            );
-                        }
-                    })}
-                </div>
-            </div>
-        );
-        return (
-            <Tooltip key="highlighter" title={<div className="dash-tooltip">{'Click to Highlight'}</div>}>
-                <div className="anchorMenu-highlighter">
-                    <ButtonDropdown key={'highlighter'} button={button} dropdownContent={dropdownContent} pdf={true} />
-                </div>
-            </Tooltip>
-        );
+        return <Group>
+            <IconButton 
+                icon={<FontAwesomeIcon icon="highlighter" style={{ transition: 'transform 0.1s', transform: 'rotate(-45deg)' }} />}
+                tooltip={'Click to Highlight'}
+                onClick={this.highlightClicked}
+                colorPicker={this.highlightColor}
+                color={StrCast(Doc.UserDoc().userColor)}
+            />
+            <ColorPicker
+                colorPickerType={'github'}
+                selectedColor={this.highlightColor}
+                setSelectedColor={color => this.changeHighlightColor(color)}
+                size={Size.XSMALL}
+            />
+        </Group>
     }
 
-    @action changeHighlightColor = (color: string, e: React.PointerEvent) => {
+    @action changeHighlightColor = (color: string) => {
         const col: ColorState = {
             hex: color,
             hsl: { a: 0, h: 0, s: 0, l: 0, source: '' },
@@ -304,8 +279,6 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
             oldHue: 0,
             source: '',
         };
-        e.preventDefault();
-        e.stopPropagation();
         this.highlightColor = Utils.colorString(col);
     };
 
@@ -339,11 +312,12 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
             this.Status === 'marquee' ? (
                 <>
                     {this.highlighter}
-                    <Tooltip key="annotate" title={<div className="dash-tooltip">Drag to Place Annotation</div>}>
-                        <button className="antimodeMenu-button annotate" ref={this._commentCont} onPointerDown={this.pointerDown} style={{ cursor: 'grab' }}>
-                            <FontAwesomeIcon icon="comment-alt" size="lg" />
-                        </button>
-                    </Tooltip>
+                    <IconButton 
+                        tooltip={'Drag to Place Annotation'} 
+                        onPointerDown={this.pointerDown} 
+                        icon={<FontAwesomeIcon icon="comment-alt"/>}
+                        color={StrCast(Doc.UserDoc().userColor)}
+                    />
                     {/* GPT Summarize icon only shows up when text is highlighted, not on marquee selection*/}
                     {AnchorMenu.Instance.StartCropDrag === unimplementedFunction && this.canSummarize() && (
                         <Tooltip key="gpt" title={<div className="dash-tooltip">Summarize with AI</div>}>
@@ -364,32 +338,35 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
                         mode={this.GPTMode}
                     />
                     {AnchorMenu.Instance.OnAudio === unimplementedFunction ? null : (
-                        <Tooltip key="annoaudiotate" title={<div className="dash-tooltip">Click to Record Annotation</div>}>
-                            <button className="antimodeMenu-button annotate" onPointerDown={this.audioDown} style={{ cursor: 'grab' }}>
-                                <FontAwesomeIcon icon="microphone" size="lg" />
-                            </button>
-                        </Tooltip>
+                        <IconButton 
+                            tooltip={'Click to Record Annotation'}
+                            onPointerDown={this.audioDown}
+                            icon={<FontAwesomeIcon icon="microphone" />}
+                            color={StrCast(Doc.UserDoc().userColor)}
+                        />
                     )}
                     {this.canEdit() && (
-                        <Tooltip key="gpttextedit" title={<div className="dash-tooltip">AI edit suggestions</div>}>
-                            <button className="antimodeMenu-button annotate" onPointerDown={this.gptEdit} style={{ cursor: 'grab' }}>
-                                <FontAwesomeIcon icon="pencil-alt" size="lg" />
-                            </button>
-                        </Tooltip>
+                        <IconButton 
+                            tooltip={'AI edit suggestions'}
+                            onPointerDown={this.gptEdit}
+                            icon={<FontAwesomeIcon icon="pencil-alt" />}
+                            color={StrCast(Doc.UserDoc().userColor)}
+                        />
                     )}
-                    <Tooltip key="link" title={<div className="dash-tooltip">Find document to link to selected text</div>}>
-                        <button className="antimodeMenu-button link" onPointerDown={this.toggleLinkPopup}>
-                            <FontAwesomeIcon style={{ position: 'absolute', transform: 'scale(1.5)' }} icon={'search'} size="lg" />
-                            <FontAwesomeIcon style={{ position: 'absolute', transform: 'scale(0.5)', transformOrigin: 'top left', top: 12, left: 12 }} icon={'link'} size="lg" />
-                        </button>
-                    </Tooltip>
-                    <LinkPopup key="popup" showPopup={this._showLinkPopup} linkCreateAnchor={this.onMakeAnchor} />,
+                    <Popup 
+                        tooltip='Find document to link to selected text'
+                        type={Type.PRIM}
+                        icon={<FontAwesomeIcon icon={'search'} />}
+                        popup={<LinkPopup key="popup" linkCreateAnchor={this.onMakeAnchor} />}
+                        color={StrCast(Doc.UserDoc().userColor)}
+                    />
                     {AnchorMenu.Instance.StartCropDrag === unimplementedFunction ? null : (
-                        <Tooltip key="crop" title={<div className="dash-tooltip">Click/Drag to create cropped image</div>}>
-                            <button className="antimodeMenu-button annotate" onPointerDown={this.cropDown} style={{ cursor: 'grab' }}>
-                                <FontAwesomeIcon icon="image" size="lg" />
-                            </button>
-                        </Tooltip>
+                        <IconButton 
+                            tooltip={'Click/Drag to create cropped image'}
+                            onPointerDown={this.cropDown}
+                            icon={<FontAwesomeIcon icon="image"/>}
+                            color={StrCast(Doc.UserDoc().userColor)}
+                        />
                     )}
                 </>
             ) : (
diff --git a/src/client/views/search/SearchBox.scss b/src/client/views/search/SearchBox.scss
index 5516cf205..a439aea3e 100644
--- a/src/client/views/search/SearchBox.scss
+++ b/src/client/views/search/SearchBox.scss
@@ -9,7 +9,6 @@
     background: none;
     z-index: 1000;
     padding: 0px;
-    overflow: scroll;
     cursor: default;
 
     .searchBox-bar {
@@ -22,7 +21,7 @@
         padding: 5px;
         top: 0px;
         position: sticky;
-        background: $light-gray;
+        overflow-y: scroll;
         border-bottom: $standard-border;
 
         .searchBox-type {
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 12c25ca09..11f22ad5e 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -17,6 +17,7 @@ import { FieldView, FieldViewProps } from '../nodes/FieldView';
 import './SearchBox.scss';
 import { fetchRecommendations } from '../newlightbox/utils';
 import { IRecommendation, Recommendation } from '../newlightbox/components';
+import { Colors } from '../global/globalEnums';
 
 const DAMPENING_FACTOR = 0.9;
 const MAX_ITERATIONS = 25;
@@ -528,7 +529,7 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
         ))
 
         return (
-            <div style={{ pointerEvents: 'all' }} className="searchBox-container">
+            <div className="searchBox-container" style={{pointerEvents: 'all', background: StrCast(Doc.UserDoc().userBackgroundColor)}}>
                 <div className="searchBox-bar">
                     {isLinkSearch ? null : (
                         <select name="type" id="searchBox-type" className="searchBox-type" onChange={this.onSelectChange}>
@@ -552,14 +553,14 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
                     />
                 </div>
                 {resultsJSX.length > 0 && <div className="searchBox-results-container">
-                    <div className="section-header">
+                    <div className="section-header" style={{background: StrCast(Doc.UserDoc().userVariantColor, Colors.MEDIUM_BLUE)}}>
                         <div className="section-title">Results</div>
                         <div className="section-subtitle">{`${validResults}` + ' result' + (validResults === 1 ? '' : 's')}</div>
                     </div>
                     <div className="searchBox-results-view">{resultsJSX}</div>
                 </div>}
                 {recommendationsJSX.length > 0 && <div className="searchBox-recommendations-container">
-                    <div className="section-header">
+                    <div className="section-header" style={{background: StrCast(Doc.UserDoc().userVariantColor, Colors.MEDIUM_BLUE)}}>
                         <div className="section-title">Recommendations</div>
                         <div className="section-subtitle">{`${validResults}` + ' result' + (validResults === 1 ? '' : 's')}</div>
                     </div>
diff --git a/src/client/views/selectedDoc/SelectedDocView.scss b/src/client/views/selectedDoc/SelectedDocView.scss
new file mode 100644
index 000000000..156dfc37b
--- /dev/null
+++ b/src/client/views/selectedDoc/SelectedDocView.scss
@@ -0,0 +1,3 @@
+.selectedDocView-container {
+    
+}
\ No newline at end of file
diff --git a/src/client/views/selectedDoc/SelectedDocView.tsx b/src/client/views/selectedDoc/SelectedDocView.tsx
new file mode 100644
index 000000000..1c9e124a2
--- /dev/null
+++ b/src/client/views/selectedDoc/SelectedDocView.tsx
@@ -0,0 +1,47 @@
+import React = require('react');
+import { Doc } from "../../../fields/Doc";
+import { observer } from "mobx-react";
+import { computed } from "mobx";
+import { StrCast } from "../../../fields/Types";
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { Colors, ListBox } from 'browndash-components';
+import { DocumentManager } from '../../util/DocumentManager';
+import { DocFocusOptions } from '../nodes/DocumentView';
+
+export interface SelectedDocViewProps {
+    selectedDocs: Doc[];
+}
+
+@observer
+export class SelectedDocView extends React.Component<SelectedDocViewProps> {
+
+    @computed get selectedDocs() {
+        return this.props.selectedDocs;
+    }
+    
+
+    render() {
+        return <div className={`selectedDocView-container`}>
+            <ListBox
+                items={this.selectedDocs.map((doc) => {
+                    const icon = Doc.toIcon(doc);
+                    const iconEle = <FontAwesomeIcon size={'1x'} icon={icon} />;
+                    const text = StrCast(doc.title)
+                    const finished = () => {
+                        
+                    };
+                    const options: DocFocusOptions = {
+                        playAudio: false,
+                    };
+                    return {
+                        text: text,
+                        val: StrCast(doc._id),
+                        icon: iconEle,
+                        onClick: () => {DocumentManager.Instance.showDocument(doc, options, finished);}
+                    }
+                })}
+                color={Colors.WHITE}
+            />
+        </div>
+    }
+}
\ No newline at end of file
diff --git a/src/client/views/selectedDoc/index.ts b/src/client/views/selectedDoc/index.ts
new file mode 100644
index 000000000..1f1db91f6
--- /dev/null
+++ b/src/client/views/selectedDoc/index.ts
@@ -0,0 +1 @@
+export * from './SelectedDocView'
\ No newline at end of file
diff --git a/src/client/views/topbar/TopBar.tsx b/src/client/views/topbar/TopBar.tsx
index b613a0e3e..1b0c6803c 100644
--- a/src/client/views/topbar/TopBar.tsx
+++ b/src/client/views/topbar/TopBar.tsx
@@ -1,5 +1,5 @@
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { Button, IconButton, FontSize, Size, Type } from 'browndash-components';
+import { Button, IconButton, FontSize, Size, Type, isDark } from 'browndash-components';
 import { action, computed, observable, reaction } from 'mobx';
 import { Tooltip } from '@mui/material';
 import { observer } from 'mobx-react';
@@ -36,9 +36,10 @@ export class TopBar extends React.Component {
         });
     };
 
-    @observable textColor: string = Colors.LIGHT_GRAY;
+    @computed get color() { return StrCast(Doc.UserDoc().userColor, Colors.LIGHT_GRAY); }
+    @computed get variantColor() { return StrCast(Doc.UserDoc().userVariantColor, Colors.MEDIUM_BLUE); }
     @computed get backgroundColor() {
-        return PingManager.Instance.IsBeating ? Colors.DARK_GRAY : Colors.MEDIUM_GRAY;
+        return PingManager.Instance.IsBeating ? StrCast(Doc.UserDoc().userBackgroundColor, Colors.DARK_GRAY) : Colors.MEDIUM_GRAY;
     }
 
     @observable happyHeart: boolean = PingManager.Instance.IsBeating;
@@ -59,16 +60,16 @@ export class TopBar extends React.Component {
         return (
             <div className="topbar-left">
                 {Doc.ActiveDashboard ? (
-                    <IconButton onClick={this.navigateToHome} icon={<FontAwesomeIcon icon="home" />} color={this.textColor} />
+                    <IconButton onClick={this.navigateToHome} icon={<FontAwesomeIcon icon="home" />} color={this.color} />
                 ) : (
                     <div className="logo-container">
                         <img className="logo" src="/assets/medium-blue-light-blue-circle.png" alt="dash logo"></img>
-                        <span style={{ color: Colors.LIGHT_GRAY, fontWeight: 200 }}>brown</span>
-                        <span style={{ color: Colors.LIGHT_BLUE, fontWeight: 500 }}>dash</span>
+                        <span style={{ color: isDark(this.backgroundColor) ? Colors.LIGHT_GRAY : Colors.DARK_GRAY, fontWeight: 200 }}>brown</span>
+                        <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.textColor} onClick={action(() => (MainView.Instance._exploreMode = !MainView.Instance._exploreMode))} />
+                    <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))} />
                 )}
             </div>
         );
@@ -97,7 +98,7 @@ export class TopBar extends React.Component {
                     text={StrCast(Doc.ActiveDashboard.title)}
                     tooltip="Open Dashboards"
                     size={Size.SMALL}
-                    color={'white'}
+                    color={this.color}
                     style={{fontWeight: 700, fontSize: '1rem'}}
                     onClick={(e: React.MouseEvent) => {
                         const dashView = Doc.ActiveDashboard && DocumentManager.Instance.getDocumentView(Doc.ActiveDashboard);
@@ -118,7 +119,7 @@ export class TopBar extends React.Component {
                     <IconButton
                         tooltip="Work on a copy of the dashboard layout"
                         size={Size.SMALL}
-                        color={this.textColor}
+                        color={this.color}
                         onClick={async () => {
                             const batch = UndoManager.StartBatch('snapshot');
                             await DashboardView.snapshotDashboard();
@@ -142,23 +143,25 @@ export class TopBar extends React.Component {
                 {Doc.ActiveDashboard && <Button
                     text={GetEffectiveAcl(Doc.GetProto(Doc.ActiveDashboard)) === AclAdmin ? 'Share' : 'View Original'}
                     type={Type.TERT}
+                    color={this.variantColor}
                     onClick={() => {
                         SharingManager.Instance.open(undefined, Doc.ActiveDashboard);
                     }}
                     size={Size.SMALL}
                 />}
-                <IconButton tooltip={"Server ⌘⇧S"} size={Size.SMALL} color={Colors.LIGHT_GRAY} onClick={ServerStats.Instance.open} icon={<FaStamp />} />
-                <IconButton tooltip={"Issue Reporter ⌘I"} size={Size.SMALL} color={Colors.LIGHT_GRAY} onClick={ReportManager.Instance.open} icon={<FaBug />} />
-                <IconButton tooltip={"Documentation ⌘D"} size={Size.SMALL} color={Colors.LIGHT_GRAY} onClick={() => window.open('https://brown-dash.github.io/Dash-Documentation/', '_blank')} icon={<FontAwesomeIcon icon="question-circle" />} />
-                <IconButton tooltip={"Settings ⌘⇧S"} size={Size.SMALL} color={Colors.LIGHT_GRAY} onClick={SettingsManager.Instance.open} icon={<FontAwesomeIcon icon="cog" />} />
+                <IconButton tooltip={"Server ⌘⇧S"} size={Size.SMALL} color={this.color} onClick={ServerStats.Instance.open} icon={<FaStamp />} />
+                <IconButton tooltip={"Issue Reporter ⌘I"} size={Size.SMALL} color={this.color} onClick={ReportManager.Instance.open} icon={<FaBug />} />
+                <IconButton tooltip={"Documentation ⌘D"} size={Size.SMALL} color={this.color} onClick={() => window.open('https://brown-dash.github.io/Dash-Documentation/', '_blank')} icon={<FontAwesomeIcon icon="question-circle" />} />
+                <IconButton tooltip={"Settings ⌘⇧S"} size={Size.SMALL} color={this.color} onClick={SettingsManager.Instance.open} icon={<FontAwesomeIcon icon="cog" />} />
                 <IconButton
                     size={Size.SMALL}
                     onClick={PingManager.Instance.showAlert}
+                    type={Type.TERT}
                     tooltip={'Server is ' + (PingManager.Instance.IsBeating ? '' : 'NOT ') + 'running'}
                     color={this.happyHeart ? Colors.LIGHT_BLUE : Colors.ERROR_RED}
                     icon={<FontAwesomeIcon icon={this.happyHeart ? 'heart' : 'heart-broken'} />}
                 />
-                {/* <Button text={'Logout'} borderRadius={5} hoverStyle={'gray'} backgroundColor={Colors.DARK_GRAY} color={this.textColor} fontSize={FontSize.SECONDARY} onClick={() => window.location.assign(Utils.prepend('/logout'))} /> */}
+                {/* <Button text={'Logout'} borderRadius={5} hoverStyle={'gray'} backgroundColor={Colors.DARK_GRAY} color={this.color} fontSize={FontSize.SECONDARY} onClick={() => window.location.assign(Utils.prepend('/logout'))} /> */}
             </div>
         );
     }
@@ -168,8 +171,9 @@ export class TopBar extends React.Component {
             //TODO:glr Add support for light / dark mode
             <div style={{ 
                 pointerEvents: 'all',
-                color: this.textColor,
-                background: this.backgroundColor, 
+                color: this.color,
+                background: this.backgroundColor,
+                // borderColor: this.color
             }} className="topbar-container">
                 <div className="topbar-inner-container">
                     {this.topbarLeft}
-- 
cgit v1.2.3-70-g09d2


From 4c8eee9811abd072d2a6adfe24eaf04f980ccf21 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 9 Aug 2023 15:21:20 -0400
Subject: updated file system to include recentlyClosed, Shared, and Dashboards
 and fixed drag drop to make sense for the filesystem.   Fixed loading
 documents to happen in one batch by fixing UPDATE_CACHED_DOCS to save only
 documents accessible from current dashboard.

---
 src/Utils.ts                                       |   2 +-
 src/client/DocServer.ts                            |  60 +-
 src/client/documents/DocumentTypes.ts              |   4 -
 src/client/documents/Documents.ts                  |  12 +-
 src/client/util/CurrentUserUtils.ts                |  37 +-
 src/client/util/DocumentManager.ts                 |   5 +-
 src/client/util/DragManager.ts                     |   4 +-
 src/client/util/GroupManager.tsx                   |   5 +-
 src/client/util/GroupMemberView.tsx                |   3 +-
 src/client/util/LinkManager.ts                     |   4 +-
 src/client/util/ReplayMovements.ts                 |   1 -
 src/client/util/ServerStats.tsx                    |  26 +-
 src/client/util/SettingsManager.tsx                |  11 +-
 src/client/util/SharingManager.tsx                 |  11 +-
 src/client/util/reportManager/ReportManager.tsx    |   5 +-
 src/client/views/DashboardView.tsx                 |  83 +--
 src/client/views/DocComponent.tsx                  |   4 +-
 src/client/views/FilterPanel.tsx                   |  18 +-
 src/client/views/LightboxView.tsx                  |   4 +-
 src/client/views/Main.tsx                          |   5 +-
 src/client/views/MainView.tsx                      |  12 +-
 src/client/views/PropertiesButtons.tsx             |   1 -
 src/client/views/PropertiesDocContextSelector.tsx  |   1 -
 src/client/views/PropertiesSection.tsx             |  80 ++-
 src/client/views/PropertiesView.tsx                | 758 ++++++++++-----------
 src/client/views/StyleProvider.tsx                 |   8 +-
 src/client/views/UndoStack.tsx                     |  43 +-
 .../views/collections/CollectionDockingView.tsx    |   7 +-
 src/client/views/collections/CollectionMenu.tsx    |   2 +-
 .../views/collections/CollectionStackingView.tsx   |   1 -
 .../views/collections/CollectionTreeView.tsx       |   1 +
 src/client/views/collections/TabDocView.tsx        |   2 +-
 src/client/views/collections/TreeView.tsx          |   2 +-
 .../collections/collectionFreeForm/MarqueeView.tsx |   1 -
 src/client/views/global/globalScripts.ts           |   1 -
 .../views/newlightbox/ExploreView/ExploreView.tsx  |   3 -
 .../components/Recommendation/Recommendation.tsx   |   1 -
 src/client/views/nodes/DataVizBox/utils/D3Utils.ts |   1 -
 src/client/views/nodes/DocumentView.tsx            |   3 +-
 src/client/views/nodes/LinkDocPreview.tsx          |   2 +-
 src/client/views/nodes/MapBox/MapBox.tsx           |   1 -
 src/client/views/nodes/ScreenshotBox.tsx           |   5 +-
 src/client/views/nodes/ScriptingBox.tsx            |   2 -
 .../views/nodes/formattedText/FormattedTextBox.tsx |  20 +-
 .../views/nodes/formattedText/RichTextRules.ts     |  26 +-
 src/client/views/pdf/AnchorMenu.tsx                |   5 +-
 src/client/views/search/SearchBox.tsx              |  78 ++-
 src/client/views/topbar/TopBar.tsx                 |  38 +-
 src/fields/Doc.ts                                  |  81 ++-
 src/fields/FieldLoader.tsx                         |   5 +-
 src/server/DashUploadUtils.ts                      |   3 +-
 51 files changed, 727 insertions(+), 771 deletions(-)

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

diff --git a/src/Utils.ts b/src/Utils.ts
index 8b9fe2aab..7f83ab8f5 100644
--- a/src/Utils.ts
+++ b/src/Utils.ts
@@ -76,7 +76,7 @@ export namespace Utils {
             });
             return returnedUri;
         } catch (e) {
-            console.log('VideoBox :' + e);
+            console.log('ConvertDataURI :' + e);
         }
     }
 
diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts
index ad5a73598..40979d631 100644
--- a/src/client/DocServer.ts
+++ b/src/client/DocServer.ts
@@ -1,16 +1,18 @@
 import { runInAction } from 'mobx';
 import * as rp from 'request-promise';
 import * as io from 'socket.io-client';
-import { Doc, Opt } from '../fields/Doc';
+import { Doc, DocListCast, Opt } from '../fields/Doc';
 import { UpdatingFromServer } from '../fields/DocSymbols';
 import { FieldLoader } from '../fields/FieldLoader';
 import { HandleUpdate, Id, Parent } from '../fields/FieldSymbols';
 import { ObjectField } from '../fields/ObjectField';
 import { RefField } from '../fields/RefField';
-import { StrCast } from '../fields/Types';
+import { DocCast, StrCast } from '../fields/Types';
 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';
 
@@ -30,35 +32,44 @@ import { GestureOverlay } from './views/GestureOverlay';
 export namespace DocServer {
     let _cache: { [id: string]: RefField | Promise<Opt<RefField>> } = {};
 
-    export function QUERY_SERVER_CACHE(title: string) {
+    export function FindDocByTitle(title: string) {
         const foundDocId = Array.from(Object.keys(_cache))
             .filter(key => _cache[key] instanceof Doc)
             .find(key => (_cache[key] as Doc).title === title);
 
         return foundDocId ? (_cache[foundDocId] as Doc) : undefined;
     }
-    let lastCacheUpdate = 0;
-    export function UPDATE_SERVER_CACHE(print: boolean = false) {
-        if (print) {
-            const strings: string[] = [];
-            Array.from(Object.keys(_cache)).forEach(key => {
-                const doc = _cache[key];
-                if (doc instanceof Doc) strings.push(StrCast(doc.author) + ' ' + StrCast(doc.title) + ' ' + StrCast(Doc.GetT(doc, 'title', 'string', true)));
-            });
-            strings.sort().forEach((str, i) => console.log(i.toString() + ' ' + str));
-        }
-        const filtered = Array.from(Object.keys(_cache)).filter(key => {
-            const doc = _cache[key] as Doc;
-            return true;
-            if (!(StrCast(doc.author).includes('.edu') || StrCast(doc.author).includes('.com')) || doc.author === Doc.CurrentUserEmail) return true;
-            return false;
+    let cacheDocumentIds = ''; // ; separate string of all documents ids in the user's working set (cached on the server)
+    export let CacheNeedsUpdate = false;
+    export function UPDATE_SERVER_CACHE() {
+        const prototypes = Object.values(DocumentType)
+            .filter(type => type !== DocumentType.NONE)
+            .map(type => _cache[type + 'Proto'])
+            .filter(doc => doc instanceof Doc)
+            .map(doc => doc as Doc);
+        const references = new Set<Doc>(prototypes);
+        Doc.FindReferences(Doc.UserDoc(), references, undefined);
+        DocListCast(DocCast(Doc.UserDoc().myLinkDatabase).data).forEach(link => {
+            if (!references.has(DocCast(link.link_anchor_1)) && !references.has(DocCast(link.link_anchor_2))) {
+                Doc.RemoveDocFromList(DocCast(Doc.UserDoc().myLinkDatabase), 'data', link);
+            }
         });
-        if (filtered.length === lastCacheUpdate) return;
-        lastCacheUpdate = filtered.length;
+        LinkManager.userLinkDBs.forEach(linkDb => Doc.FindReferences(linkDb, references, undefined));
+        const filtered = Array.from(references);
+
+        const newCacheUpdate = filtered.map(doc => doc[Id]).join(';');
+        if (newCacheUpdate === cacheDocumentIds) return;
+        cacheDocumentIds = newCacheUpdate;
+
+        // print out cached docs
+        console.log('Set cached docs = ');
+        const is_filtered = filtered.filter(doc => !Doc.IsSystem(doc));
+        const strings = is_filtered.map(doc => StrCast(doc.title) + ' ' + (Doc.IsDataProto(doc) ? '(data)' : '(embedding)'));
+        strings.sort().forEach((str, i) => console.log(i.toString() + ' ' + str));
 
         rp.post(Utils.prepend('/setCacheDocumentIds'), {
             body: {
-                cacheDocumentIds: filtered.join(';'),
+                cacheDocumentIds,
             },
             json: true,
         });
@@ -353,7 +364,7 @@ export namespace DocServer {
         // i) which documents need to be fetched
         // ii) which are already in the process of being fetched
         // iii) which already exist in the cache
-        for (const id of ids) {
+        for (const id of ids.filter(id => id)) {
             const cached = _cache[id];
             if (cached === undefined) {
                 defaultPromises.push({
@@ -382,7 +393,7 @@ export namespace DocServer {
             // fields for the given ids. This returns a promise, which, when resolved, indicates that all the JSON serialized versions of
             // the fields have been returned from the server
             console.log('Requesting ' + requestedIds.length);
-            FieldLoader.active && runInAction(() => (FieldLoader.ServerLoadStatus.requested = requestedIds.length));
+            setTimeout(() => runInAction(() => (FieldLoader.ServerLoadStatus.requested = requestedIds.length)));
             const serializedFields = await Utils.EmitCallback(_socket, MessageStore.GetRefFields, requestedIds);
 
             // 3) when the serialized RefFields have been received, go head and begin deserializing them into objects.
@@ -392,7 +403,7 @@ export namespace DocServer {
             console.log('deserializing ' + serializedFields.length + ' fields');
             for (const field of serializedFields) {
                 processed++;
-                if (FieldLoader.active && processed % 150 === 0) {
+                if (processed % 150 === 0) {
                     runInAction(() => (FieldLoader.ServerLoadStatus.retrieved = processed));
                     await new Promise(res => setTimeout(res)); // force loading to yield to splash screen rendering to update progress
                 }
@@ -478,6 +489,7 @@ export namespace DocServer {
      * @param field the [RefField] to be serialized and sent to the server to be stored in the database
      */
     export function CreateField(field: RefField) {
+        CacheNeedsUpdate = true;
         _CreateField(field);
     }
 
diff --git a/src/client/documents/DocumentTypes.ts b/src/client/documents/DocumentTypes.ts
index b629d9b8c..1d0ddce40 100644
--- a/src/client/documents/DocumentTypes.ts
+++ b/src/client/documents/DocumentTypes.ts
@@ -14,13 +14,11 @@ export enum DocumentType {
     INK = 'ink',
     SCREENSHOT = 'screenshot',
     FONTICON = 'fonticonbox',
-    FILTER = 'filter',
     SEARCH = 'search', // search query
     LABEL = 'label', // simple text label
     BUTTON = 'button', // onClick button
     WEBCAM = 'webcam', // webcam
     CONFIG = 'config', // configuration document intended to specify a view layout configuration, but not be directly rendered (e.g., for saving the page# of a PDF, or view transform of a collection)
-    DATE = 'date', // calendar view of a date
     SCRIPTING = 'script', // script editor
     EQUATION = 'equation', // equation editor
     FUNCPLOT = 'funcplot', // function plotter
@@ -31,14 +29,12 @@ export enum DocumentType {
 
     // special purpose wrappers that either take no data or are compositions of lower level types
     LINK = 'link',
-    LINKANCHOR = 'linkanchor',
     IMPORT = 'import',
     SLIDER = 'slider',
     PRES = 'presentation',
     PRESELEMENT = 'preselement',
     COLOR = 'color',
     YOUTUBE = 'youtube',
-    SEARCHITEM = 'searchitem',
     COMPARISON = 'comparison',
     GROUP = 'group',
 
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 8eeceaa15..fccad80ee 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -1,5 +1,5 @@
 import { IconProp } from '@fortawesome/fontawesome-svg-core';
-import { action, runInAction } from 'mobx';
+import { action, reaction, runInAction } from 'mobx';
 import { basename } from 'path';
 import { DateField } from '../../fields/DateField';
 import { Doc, DocListCast, Field, Opt, updateCachedAcls } from '../../fields/Doc';
@@ -744,6 +744,10 @@ export namespace Docs {
                 // an entry dedicated to the given DocumentType)
                 target && PrototypeMap.set(type, target);
             });
+            reaction(
+                () => (proto => StrCast(proto?.BROADCAST_MESSAGE))(DocServer.GetCachedRefField('rtfProto') as Doc),
+                msg => msg && alert(msg)
+            );
         }
 
         /**
@@ -887,8 +891,6 @@ export namespace Docs {
                 DocUtils.MakeLinkToActiveAudio(() => viewDoc);
             }
 
-            Doc.AddFileOrphan(dataDoc);
-
             updateCachedAcls(dataDoc);
             updateCachedAcls(viewDoc);
 
@@ -1150,9 +1152,6 @@ export namespace Docs {
         export function FontIconDocument(options?: DocumentOptions) {
             return InstanceFromProto(Prototypes.get(DocumentType.FONTICON), undefined, { ...(options || {}) });
         }
-        export function FilterDocument(options?: DocumentOptions) {
-            return InstanceFromProto(Prototypes.get(DocumentType.FILTER), undefined, { ...(options || {}) });
-        }
 
         export function PresElementBoxDocument() {
             return Prototypes.get(DocumentType.PRESELEMENT);
@@ -1872,7 +1871,6 @@ export namespace DocUtils {
     export function copyDragFactory(dragFactory: Doc) {
         if (!dragFactory) return undefined;
         const ndoc = dragFactory.isTemplateDoc ? Doc.ApplyTemplate(dragFactory) : Doc.MakeCopy(dragFactory, true);
-        ndoc && Doc.AddFileOrphan(Doc.GetProto(ndoc));
         if (ndoc && dragFactory['dragFactory_count'] !== undefined) {
             dragFactory['dragFactory_count'] = NumCast(dragFactory['dragFactory_count']) + 1;
             Doc.SetInPlace(ndoc, 'title', ndoc.title + ' ' + NumCast(dragFactory['dragFactory_count']).toString(), true);
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 21bcec6d1..e8262ff3b 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -152,7 +152,7 @@ export class CurrentUserUtils {
             { noteType: "Idea", backgroundColor: "pink", icon: "lightbulb" },
             { noteType: "Topic", backgroundColor: "lightblue", icon: "book-open" }];
         const reqdNoteList = reqdTempOpts.map(opts => {
-            const reqdOpts = {...opts, title: "text", width:200, layout_autoHeight: true, layout_fitWidth: true};
+            const reqdOpts = {...opts, isSystem:true, title: "text", width:200, layout_autoHeight: true, layout_fitWidth: true};
             const noteType = tempNotes ? DocListCast(tempNotes.data).find(doc => doc.noteType === opts.noteType): undefined;
             return DocUtils.AssignOpts(noteType, reqdOpts) ?? MakeTemplate(Docs.Create.TextDocument("",reqdOpts), true, opts.noteType??"Note");
         });
@@ -339,7 +339,7 @@ export class CurrentUserUtils {
     }
 
     /// returns descriptions needed to buttons for the left sidebar to open up panes displaying different collections of documents
-    static leftSidebarMenuBtnDescriptions(doc: Doc):{title:string, target:Doc, icon:string, toolTip: string, scripts:{[key:string]:any}, funcs?:{[key:string]:any}}[] {
+    static leftSidebarMenuBtnDescriptions(doc: Doc):{title:string, target:Doc, icon:string, toolTip: string, scripts:{[key:string]:any}, funcs?:{[key:string]:any}, hidden?: boolean}[] {
       const badgeValue = "((len) => len && len !== '0' ? len: undefined)(docList(self.target.data).filter(doc => !docList(self.target.viewed).includes(doc)).length.toString())"; 
       const getActiveDashTrails = "Doc.ActiveDashboard?.myTrails";
         return [
@@ -348,7 +348,7 @@ export class CurrentUserUtils {
             { title: "Files",           toolTip: "Files",           target: this.setupFilesystem(doc, "myFilesystem"),         ignoreClick: true, icon: "folder-open", },
             { title: "Tools",           toolTip: "Tools",           target: this.setupToolsBtnPanel(doc, "myTools"),           ignoreClick: true, icon: "wrench",      funcs: {hidden: "IsNoviceMode()"} },
             { title: "Imports",         toolTip: "Imports ⌘I",      target: this.setupImportSidebar(doc, "myImports"),         ignoreClick:false, icon: "upload",      },
-            { title: "Closed",          toolTip: "Recently Closed", target: this.setupRecentlyClosed(doc, "myRecentlyClosed"), ignoreClick: true, icon: "archive",     },
+            { title: "Closed",          toolTip: "Recently Closed", target: this.setupRecentlyClosed(doc, "myRecentlyClosed"), ignoreClick: true, icon: "archive",     hidden: true }, // this doc is hidden from the Sidebar, but it's still being used in MyFilesystem which ignores the hidden field
             { title: "Shared",          toolTip: "Shared Docs",     target: Doc.MySharedDocs,                                  ignoreClick: true, icon: "users",       funcs: {badgeValue: badgeValue}},
             { title: "Trails",          toolTip: "Trails ⌘R",       target: Doc.UserDoc(),                                     ignoreClick: true, icon: "pres-trail",  funcs: {target: getActiveDashTrails}},
             { title: "User Doc",        toolTip: "User Doc",        target: this.setupUserDocView(doc, "myUserDocView"),       ignoreClick: true, icon: "address-card",funcs: {hidden: "IsNoviceMode()"} },
@@ -357,17 +357,17 @@ export class CurrentUserUtils {
 
     /// the empty panel that is filled with whichever left menu button's panel has been selected
     static setupLeftSidebarPanel(doc: Doc, field="myLeftSidebarPanel") {
-        DocUtils.AssignDocField(doc, field, (opts) => Doc.assign(new Doc(), opts as any), {isSystem:true, undoIgnoreFields: new List<string>(['proto'])});
+        DocUtils.AssignDocField(doc, field, (opts) => Doc.assign(new Doc(), opts as any), {title:"leftSidebarPanel", isSystem:true, undoIgnoreFields: new List<string>(['proto'])});
     }
 
     /// Initializes the left sidebar menu buttons and the panels they open up
     static setupLeftSidebarMenu(doc: Doc, field="myLeftSidebarMenu") {
         this.setupLeftSidebarPanel(doc);
         const myLeftSidebarMenu = DocCast(doc[field]);
-        const menuBtns = CurrentUserUtils.leftSidebarMenuBtnDescriptions(doc).map(({ title, target, icon, toolTip, scripts, funcs }) => {
+        const menuBtns = CurrentUserUtils.leftSidebarMenuBtnDescriptions(doc).map(({ title, target, icon, toolTip, hidden, scripts, funcs }) => {
             const btnDoc = myLeftSidebarMenu ? DocListCast(myLeftSidebarMenu.data).find(doc => doc.title === title) : undefined;
             const reqdBtnOpts:DocumentOptions = {
-                title, icon, target, toolTip, btnType: ButtonType.MenuButton, isSystem: true, undoIgnoreFields: new List<string>(['height', 'data_columnHeaders']), dontRegisterView: true,
+                title, icon, target, toolTip, hidden, btnType: ButtonType.MenuButton, isSystem: true, undoIgnoreFields: new List<string>(['height', 'data_columnHeaders']), dontRegisterView: true,
                 _width: 60, _height: 60,  _dragOnlyWithinContainer: true, _layout_hideContextMenu: true,
             };
             return DocUtils.AssignScripts(DocUtils.AssignOpts(btnDoc, reqdBtnOpts) ?? Docs.Create.FontIconDocument(reqdBtnOpts), scripts, funcs);
@@ -495,7 +495,7 @@ export class CurrentUserUtils {
         const reqdOpts:DocumentOptions = {
             title: "My Dashboards", childHideLinkButton: true, treeViewFreezeChildren: "remove|add", treeViewHideTitle: true, layout_boxShadow: "0 0", childDontRegisterViews: true,
             dropAction: "same", treeViewType: TreeViewType.fileSystem, isFolder: true, isSystem: true,  treeViewTruncateTitleWidth: 350, ignoreClick: true, 
-            layout_headerButton: newDashboardButton, childDragAction: "embed",
+            layout_headerButton: newDashboardButton, childDragAction: "none",
             _layout_showTitle: "title", _height: 400, _gridGap: 5, _forceActive: true, _lockedPosition: true,
             contextMenuLabels:new List<string>(contextMenuLabels),
             contextMenuIcons:new List<string>(contextMenuIcons),
@@ -519,7 +519,6 @@ export class CurrentUserUtils {
     /// initializes the left sidebar File system pane
     static setupFilesystem(doc: Doc, field:string) {
         var myFilesystem = DocCast(doc[field]);
-        const myFileOrphans = DocUtils.AssignDocField(doc, "myFileOrphans", (opts) => Docs.Create.TreeDocument([], opts), { title: "Unfiled", undoIgnoreFields:new List<string>(['treeViewSortCriterion']), _dragOnlyWithinContainer: true, isSystem: true, isFolder: true });
         
         const newFolder = `TreeView_addNewFolder()`;
         const newFolderOpts: DocumentOptions = {
@@ -530,14 +529,15 @@ export class CurrentUserUtils {
         const newFolderButton = DocUtils.AssignScripts(DocUtils.AssignOpts(DocCast(myFilesystem?.layout_headerButton), newFolderOpts) ?? Docs.Create.FontIconDocument(newFolderOpts), newFolderScript);
         
         const reqdOpts:DocumentOptions = { _layout_showTitle: "title", _height: 100, _gridGap: 5, _forceActive: true, _lockedPosition: true, 
-            title: "My Documents", layout_headerButton: newFolderButton, treeViewHideTitle: true, dropAction: "proto", isSystem: true,
+            title: "My Documents", layout_headerButton: newFolderButton, treeViewHideTitle: true, dropAction: 'add', isSystem: true,
             isFolder: true, treeViewType: TreeViewType.fileSystem, childHideLinkButton: true, layout_boxShadow: "0 0", childDontRegisterViews: true, 
             treeViewTruncateTitleWidth: 350, ignoreClick: true, childDragAction: "embed",
             childContextMenuLabels: new List<string>(["Create new folder"]),
             childContextMenuIcons: new List<string>(["plus"]),
             layout_explainer: "This is your file manager where you can create folders to keep track of documents independently of your dashboard."
         };
-        myFilesystem = DocUtils.AssignDocField(doc, field, (opts, items) => Docs.Create.TreeDocument(items??[], opts), reqdOpts, [myFileOrphans]);
+        const fileFolders = new Set(DocListCast(DocCast(doc[field])?.data));
+        myFilesystem = DocUtils.AssignDocField(doc, field, (opts, items) => Docs.Create.TreeDocument(items??[], opts), reqdOpts, Array.from(fileFolders));
         const childContextMenuScripts = [newFolder];
         if (Cast(myFilesystem.childContextMenuScripts, listSpec(ScriptField), null)?.length !== childContextMenuScripts.length) {
             myFilesystem.childContextMenuScripts = new List<ScriptField>(childContextMenuScripts.map(script => ScriptField.MakeFunction(script)!));
@@ -547,8 +547,8 @@ export class CurrentUserUtils {
 
     /// initializes the panel displaying docs that have been recently closed
     static setupRecentlyClosed(doc: Doc, field:string) {
-        const reqdOpts:DocumentOptions = { _layout_showTitle: "title", _lockedPosition: true, _gridGap: 5, _forceActive: true, 
-            title: "My Recently Closed", childHideLinkButton: true, treeViewHideTitle: true, childDragAction: "embed", isSystem: true,
+        const reqdOpts:DocumentOptions = { _layout_showTitle: "title", _lockedPosition: true, _gridGap: 5, _forceActive: true, isFolder: true,
+            title: "My Recently Closed", childHideLinkButton: true, treeViewHideTitle: true, childDragAction: "move", isSystem: true,
             treeViewTruncateTitleWidth: 350, ignoreClick: true,  layout_boxShadow: "0 0", childDontRegisterViews: true, dropAction: "same",
             contextMenuLabels: new List<string>(["Empty recently closed"]),
             contextMenuIcons:new List<string>(["trash"]),
@@ -562,8 +562,6 @@ export class CurrentUserUtils {
             toolTip: "Empty recently closed",};
         DocUtils.AssignDocField(recentlyClosed, "layout_headerButton", (opts) => Docs.Create.FontIconDocument(opts), clearBtnsOpts, undefined, {onClick: clearAll("self.target")});
 
-        //if (recentlyClosed.layout_headerButton !== clearDocsButton) Doc.GetProto(recentlyClosed).layout_headerButton = clearDocsButton;
-        
         if (!Cast(recentlyClosed.contextMenuScripts, listSpec(ScriptField),null)?.find((script) => script.script.originalScript === clearAll("self"))) {
             recentlyClosed.contextMenuScripts = new List<ScriptField>([ScriptField.MakeScript(clearAll("self"))!])
         }
@@ -777,6 +775,7 @@ export class CurrentUserUtils {
             const linkDocs = new Doc(linkDatabaseId, true);
             linkDocs.title = "LINK DATABASE: " + Doc.CurrentUserEmail;
             linkDocs.author = Doc.CurrentUserEmail;
+            linkDocs.isSystem = true;
             linkDocs.data = new List<Doc>([]);
             linkDocs["acl-Guest"] = SharingPermissions.Augment;
             doc.myLinkDatabase = new PrefetchProxy(linkDocs);
@@ -877,11 +876,13 @@ export class CurrentUserUtils {
         this.setupDockedButtons(doc);  // the bottom bar of font icons
         this.setupLeftSidebarMenu(doc); // the left-side column of buttons that open their contents in a flyout panel on the left
         this.setupDocTemplates(doc); // sets up the template menu of templates
-        this.setupFieldInfos(doc); // sets up the collection of field info descriptions for each possible DocumentOption
+        //this.setupFieldInfos(doc); // sets up the collection of field info descriptions for each possible DocumentOption
         DocUtils.AssignDocField(doc, "globalScriptDatabase", (opts) =>  Docs.Prototypes.MainScriptDocument(), {});
-        DocUtils.AssignDocField(doc, "myHeaderBar", (opts) => Docs.Create.MulticolumnDocument([], opts), { title: "header bar", isSystem: true, childDocumentsActive:false, dropAction: 'move'}); // drop down panel at top of dashboard for stashing documents
+        DocUtils.AssignDocField(doc, "myHeaderBar", (opts) => Docs.Create.MulticolumnDocument([], opts), { title: "My Header Bar", isSystem: true, childDocumentsActive:false, dropAction: 'move'}); // drop down panel at top of dashboard for stashing documents
         
+        Doc.AddDocToList(Doc.MyFilesystem, undefined, Doc.MyDashboards)
         Doc.AddDocToList(Doc.MyFilesystem, undefined, Doc.MySharedDocs)
+        Doc.AddDocToList(Doc.MyFilesystem, undefined, Doc.MyRecentlyClosed)
 
         if (doc.activeDashboard instanceof Doc) {
             // undefined means ColorScheme.Light until all CSS is updated with values for each color scheme (e.g., see MainView.scss, DocumentDecorations.scss)
@@ -889,7 +890,7 @@ export class CurrentUserUtils {
         }
         new LinkManager();
 
-        setTimeout(DocServer.UPDATE_SERVER_CACHE, 2500);
+        DocServer.CacheNeedsUpdate && setTimeout(DocServer.UPDATE_SERVER_CACHE, 2500);
         setInterval(DocServer.UPDATE_SERVER_CACHE, 120000);
         return doc;
     }
@@ -923,11 +924,9 @@ export class CurrentUserUtils {
                 {
                     const ids = result.cacheDocumentIds.split(";");
                     const batch = 30000;
-                    FieldLoader.active = true;
                     for (let i = 0; i < ids.length; i = Math.min(ids.length, i+batch)) {
                         await DocServer.GetRefFields(ids.slice(i, i+batch));
                     }
-                    FieldLoader.active = false;
                 }
                 return result;
             } else {
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 8e4e0d8f3..42132c2d7 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -75,7 +75,7 @@ export class DocumentManager {
 
     @action
     public AddView = (view: DocumentView) => {
-        //console.log("MOUNT " + view.props.Document.title + "/" + view.props.LayoutTemplateString);
+        if (view.props.LayoutTemplateString?.includes(KeyValueBox.name)) return;
         if (view.props.LayoutTemplateString?.includes(LinkAnchorBox.name)) {
             const viewAnchorIndex = view.props.LayoutTemplateString.includes('link_anchor_2') ? 'link_anchor_2' : 'link_anchor_1';
             const link = view.rootDoc;
@@ -251,6 +251,7 @@ export class DocumentManager {
         options: DocFocusOptions, // options for how to navigate to target
         finished?: (changed: boolean) => void // func called after focusing on target with flag indicating whether anything needed to be done.
     ) => {
+        Doc.RemoveDocFromList(Doc.MyRecentlyClosed, undefined, targetDoc);
         const docContextPath = DocumentManager.GetContextPath(targetDoc, true);
         if (docContextPath.some(doc => doc.hidden)) options.toggleTarget = false;
         let rootContextView =
@@ -335,7 +336,7 @@ export function DocFocusOrOpen(doc: Doc, options: DocFocusOptions = { willZoomCe
         if (dv && (!containingDoc || dv.props.docViewPath().lastElement()?.Document === containingDoc)) {
             DocumentManager.Instance.showDocumentView(dv, options).then(() => dv && Doc.linkFollowHighlight(dv.rootDoc));
         } else {
-            const container = DocCast(containingDoc ?? doc.embedContainer ?? doc);
+            const container = DocCast(containingDoc ?? doc.embedContainer ?? Doc.BestEmbedding(doc));
             const showDoc = !Doc.IsSystem(container) ? container : doc;
             options.toggleTarget = undefined;
             DocumentManager.Instance.showDocument(showDoc, options, () => DocumentManager.Instance.showDocument(doc, { ...options, openLocation: undefined })).then(() => {
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 85101fcab..f4ff38515 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -15,7 +15,7 @@ import { SelectionManager } from './SelectionManager';
 import { SnappingManager } from './SnappingManager';
 import { UndoManager } from './UndoManager';
 
-export type dropActionType = 'embed' | 'copy' | 'move' | 'same' | 'proto' | 'none' | undefined; // undefined = move, "same" = move but don't call dropPropertiesToRemove
+export type dropActionType = 'embed' | 'copy' | 'move' | 'add' | 'same' | 'proto' | 'none' | undefined; // undefined = move, "same" = move but don't call dropPropertiesToRemove
 
 /**
  * Initialize drag
@@ -213,6 +213,8 @@ export namespace DragManager {
                                 ? addAudioTag(ScriptCast(d.onDragStart).script.run({ this: d }).result)
                                 : docDragData.dropAction === 'embed'
                                 ? Doc.BestEmbedding(d)
+                                : docDragData.dropAction === 'add'
+                                ? d
                                 : docDragData.dropAction === 'proto'
                                 ? Doc.GetProto(d)
                                 : docDragData.dropAction === 'copy'
diff --git a/src/client/util/GroupManager.tsx b/src/client/util/GroupManager.tsx
index e406d89e7..f35844020 100644
--- a/src/client/util/GroupManager.tsx
+++ b/src/client/util/GroupManager.tsx
@@ -16,6 +16,7 @@ import { listSpec } from '../../fields/Schema';
 import { DateField } from '../../fields/DateField';
 import { Id } from '../../fields/FieldSymbols';
 import { Button, IconButton, Size, Type } from 'browndash-components';
+import { SettingsManager } from './SettingsManager';
 
 /**
  * Interface for options for the react-select component
@@ -281,7 +282,7 @@ export class GroupManager extends React.Component<{}> {
      */
     private get groupCreationModal() {
         const contents = (
-            <div className="group-create" style={{ background: StrCast(Doc.UserDoc().userBackgroundColor), color: StrCast(Doc.UserDoc().userColor) }}>
+            <div className="group-create" style={{ background: SettingsManager.Instance.userBackgroundColor, color: SettingsManager.Instance.userColor }}>
                 <div className="group-heading" style={{ marginBottom: 0 }}>
                     <p>
                         <b>New Group</b>
@@ -366,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: StrCast(Doc.UserDoc().userBackgroundColor), color: StrCast(Doc.UserDoc().userColor) }}>
+            <div className="group-interface" style={{ background: SettingsManager.Instance.userBackgroundColor, color: SettingsManager.Instance.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 057f94f64..535d8ccc2 100644
--- a/src/client/util/GroupMemberView.tsx
+++ b/src/client/util/GroupMemberView.tsx
@@ -9,6 +9,7 @@ import { MainViewModal } from '../views/MainViewModal';
 import { GroupManager, UserOptions } from './GroupManager';
 import './GroupMemberView.scss';
 import { Button, IconButton, Size, Type } from 'browndash-components';
+import { SettingsManager } from './SettingsManager';
 
 interface GroupMemberViewProps {
     group: Doc;
@@ -28,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: StrCast(Doc.UserDoc().userBackgroundColor), color: StrCast(Doc.UserDoc().userColor) }}>
+            <div className="editing-interface" style={{ background: SettingsManager.Instance.userBackgroundColor, color: SettingsManager.Instance.userColor }}>
                 <div className="editing-header">
                     <input
                         className="group-title"
diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts
index c7f092565..ef4b21b05 100644
--- a/src/client/util/LinkManager.ts
+++ b/src/client/util/LinkManager.ts
@@ -1,7 +1,8 @@
-import { action, observable, observe } from 'mobx';
+import { action, observable, observe, runInAction } from 'mobx';
 import { computedFn } from 'mobx-utils';
 import { Doc, DocListCast, DocListCastAsync, Field, Opt } from '../../fields/Doc';
 import { DirectLinks } from '../../fields/DocSymbols';
+import { FieldLoader } from '../../fields/FieldLoader';
 import { List } from '../../fields/List';
 import { ProxyField } from '../../fields/Proxy';
 import { Cast, DocCast, PromiseValue, StrCast } from '../../fields/Types';
@@ -132,6 +133,7 @@ export class LinkManager {
             },
             true
         );
+        runInAction(() => (FieldLoader.ServerLoadStatus.message = 'links'));
         LinkManager.addLinkDB(Doc.LinkDBDoc());
     }
 
diff --git a/src/client/util/ReplayMovements.ts b/src/client/util/ReplayMovements.ts
index cbc465d6a..d99630f82 100644
--- a/src/client/util/ReplayMovements.ts
+++ b/src/client/util/ReplayMovements.ts
@@ -187,7 +187,6 @@ export class ReplayMovements {
                 } else {
                     // tab wasn't open - open it and play the movement
                     const openedColFFView = this.openTab(movement.doc);
-                    console.log('openedColFFView', openedColFFView);
                     openedColFFView && this.zoomAndPan(movement, openedColFFView);
                 }
 
diff --git a/src/client/util/ServerStats.tsx b/src/client/util/ServerStats.tsx
index 6a6ec158e..3c7c35a7e 100644
--- a/src/client/util/ServerStats.tsx
+++ b/src/client/util/ServerStats.tsx
@@ -6,6 +6,7 @@ import './SharingManager.scss';
 import { PingManager } from './PingManager';
 import { StrCast } from '../../fields/Types';
 import { Doc } from '../../fields/Doc';
+import { SettingsManager } from './SettingsManager';
 
 @observer
 export class ServerStats extends React.Component<{}> {
@@ -42,21 +43,22 @@ export class ServerStats extends React.Component<{}> {
      */
     @computed get sharingInterface() {
         return (
-            <div style={{
-                display: "flex",
-                height: 300,
-                width: 400,
-                background: StrCast(Doc.UserDoc().userBackgroundColor),
-                opacity: 0.6}}>
-                    <div style={{width: 300,height: 100,margin: "auto",display: "flex",flexDirection: "column"}}>
-                        {PingManager.Instance.IsBeating ? 'The server connection is active' :
-                            'The server connection has been interrupted.NOTE: Any changes made will appear to persist but will be lost after a browser refreshes.'}
-                          
-                    <br/>
+            <div
+                style={{
+                    display: 'flex',
+                    height: 300,
+                    width: 400,
+                    background: SettingsManager.Instance?.userBackgroundColor,
+                    opacity: 0.6,
+                }}>
+                <div style={{ width: 300, height: 100, margin: 'auto', display: 'flex', flexDirection: 'column' }}>
+                    {PingManager.Instance.IsBeating ? 'The server connection is active' : 'The server connection has been interrupted.NOTE: Any changes made will appear to persist but will be lost after a browser refreshes.'}
+
+                    <br />
                     <span>Active users:{this._stats?.socketMap.length}</span>
                     {this._stats?.socketMap.map((user: any) => (
                         <p>{user.username}</p>
-                    ))}  
+                    ))}
                 </div>
             </div>
         );
diff --git a/src/client/util/SettingsManager.tsx b/src/client/util/SettingsManager.tsx
index b8e327968..573900825 100644
--- a/src/client/util/SettingsManager.tsx
+++ b/src/client/util/SettingsManager.tsx
@@ -1,10 +1,11 @@
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { Button, ColorPicker, Dropdown, DropdownType, EditableText, Group, NumberDropdown, Size, Toggle, ToggleType, Type } from 'browndash-components';
 import { action, computed, observable, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
-import { ColorState, SketchPicker } from 'react-color';
+import { BsGoogle } from 'react-icons/bs';
+import { FaFillDrip, FaPalette } from 'react-icons/fa';
 import { Doc } from '../../fields/Doc';
-import { Id } from '../../fields/FieldSymbols';
 import { BoolCast, Cast, StrCast } from '../../fields/Types';
 import { addStyleSheet, addStyleSheetRule, Utils } from '../../Utils';
 import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager';
@@ -12,13 +13,9 @@ import { DocServer } from '../DocServer';
 import { Networking } from '../Network';
 import { MainViewModal } from '../views/MainViewModal';
 import { FontIconBox } from '../views/nodes/FontIconBox/FontIconBox';
-import { DragManager } from './DragManager';
 import { GroupManager } from './GroupManager';
 import './SettingsManager.scss';
 import { undoBatch } from './UndoManager';
-import { Button, ColorPicker, Dropdown, DropdownType, EditableText, Group, NumberDropdown, Size, Toggle, ToggleType, Type } from 'browndash-components';
-import { BsGoogle } from 'react-icons/bs';
-import { FaFillDrip, FaPalette } from 'react-icons/fa';
 const higflyout = require('@hig/flyout');
 export const { anchorPoints } = higflyout;
 export const Flyout = higflyout.default;
@@ -39,6 +36,7 @@ export enum freeformScrollMode {
 
 @observer
 export class SettingsManager extends React.Component<{}> {
+    static Version = 'v0.5';
     public static Instance: SettingsManager;
     static _settingsStyle = addStyleSheet();
     @observable public isOpen = false;
@@ -452,6 +450,7 @@ export class SettingsManager extends React.Component<{}> {
                     </div>
 
                     <div className="settings-user">
+                        <div style={{ color: 'black' }}>{SettingsManager.Version}</div>
                         <div className="settings-username" style={{ color: this.userBackgroundColor }}>
                             {Doc.CurrentUserEmail}
                         </div>
diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx
index cadcb1f8a..6171c01d7 100644
--- a/src/client/util/SharingManager.tsx
+++ b/src/client/util/SharingManager.tsx
@@ -8,6 +8,7 @@ import Select from 'react-select';
 import * as RequestPromise from 'request-promise';
 import { Doc, DocListCast, DocListCastAsync, HierarchyMapping, ReverseHierarchyMap } from '../../fields/Doc';
 import { AclAdmin, AclPrivate, DocAcl, DocData } from '../../fields/DocSymbols';
+import { FieldLoader } from '../../fields/FieldLoader';
 import { Id } from '../../fields/FieldSymbols';
 import { StrCast } from '../../fields/Types';
 import { distributeAcls, GetEffectiveAcl, normalizeEmail, SharingPermissions, TraceMobx } from '../../fields/util';
@@ -23,6 +24,7 @@ import { GroupManager, UserOptions } from './GroupManager';
 import { GroupMemberView } from './GroupMemberView';
 import { LinkManager } from './LinkManager';
 import { SelectionManager } from './SelectionManager';
+import { SettingsManager } from './SettingsManager';
 import './SharingManager.scss';
 import { undoable } from './UndoManager';
 
@@ -136,6 +138,7 @@ export class SharingManager extends React.Component<{}> {
             this.populating = true;
             const userList = await RequestPromise.get(Utils.prepend('/getUsers'));
             const raw = (JSON.parse(userList) as User[]).filter(user => user.email !== 'guest' && user.email !== Doc.CurrentUserEmail);
+            runInAction(() => (FieldLoader.ServerLoadStatus.message = 'users'));
             const docs = await DocServer.GetRefFields(raw.reduce((list, user) => [...list, user.sharingDocumentId, user.linkDatabaseId], [] as string[]));
             raw.map(
                 action((newUser: User) => {
@@ -144,7 +147,7 @@ export class SharingManager extends React.Component<{}> {
                     if (sharingDoc instanceof Doc && linkDatabase instanceof Doc) {
                         if (!this.users.find(user => user.user.email === newUser.email)) {
                             this.users.push({ user: newUser, sharingDoc, linkDatabase, userColor: StrCast(sharingDoc.userColor) });
-                            LinkManager.addLinkDB(linkDatabase);
+                            //LinkManager.addLinkDB(linkDatabase);
                         }
                     }
                 })
@@ -525,10 +528,10 @@ export class SharingManager extends React.Component<{}> {
             const permissions = uniform ? StrCast(targetDoc?.[groupKey]) : '-multiple-';
 
             return !permissions ? null : (
-                <div key={groupKey} className={'container'} style={{ background: StrCast(Doc.UserDoc().userBackgroundColor), color: StrCast(Doc.UserDoc().userColor) }}>
+                <div key={groupKey} className={'container'} style={{ background: SettingsManager.Instance.userBackgroundColor, color: SettingsManager.Instance.userColor }}>
                     <div className={'padding'}>{StrCast(group.title)}</div>
                     &nbsp;
-                    {group instanceof Doc ? <IconButton icon={<FontAwesomeIcon icon={'info-circle'} />} size={Size.XSMALL} color={StrCast(Doc.UserDoc().userColor)} onClick={action(() => (GroupManager.Instance.currentGroup = group))} /> : null}
+                    {group instanceof Doc ? <IconButton icon={<FontAwesomeIcon icon={'info-circle'} />} size={Size.XSMALL} color={SettingsManager.Instance.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)}>
@@ -550,7 +553,7 @@ export class SharingManager extends React.Component<{}> {
                 <div
                     className="sharing-contents"
                     style={{
-                        background: StrCast(Doc.UserDoc().userBackgroundColor),
+                        background: SettingsManager.Instance.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 e684bd637..7aad0f2b1 100644
--- a/src/client/util/reportManager/ReportManager.tsx
+++ b/src/client/util/reportManager/ReportManager.tsx
@@ -19,6 +19,7 @@ import { BugType, FileData, Priority, ReportForm, ViewState, bugDropdownItems, d
 import { Filter, FormInput, FormTextArea, IssueCard, IssueView, Tag } from './ReportManagerComponents';
 import { StrCast } from '../../../fields/Types';
 import { MdRefresh } from 'react-icons/md';
+import { SettingsManager } from '../SettingsManager';
 const higflyout = require('@hig/flyout');
 export const { anchorPoints } = higflyout;
 export const Flyout = higflyout.default;
@@ -213,11 +214,11 @@ export class ReportManager extends React.Component<{}> {
      * @returns the component that dispays all issues
      */
     private viewIssuesComponent = () => {
-        const darkMode = isDarkMode(StrCast(Doc.UserDoc().userBackgroundColor));
+        const darkMode = isDarkMode(SettingsManager.Instance.userBackgroundColor);
         const colors = darkMode ? darkColors : lightColors;
 
         return (
-            <div className="view-issues" style={{ backgroundColor: StrCast(Doc.UserDoc().userBackgroundColor), color: colors.text }}>
+            <div className="view-issues" style={{ backgroundColor: SettingsManager.Instance.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/DashboardView.tsx b/src/client/views/DashboardView.tsx
index ae55c8ebf..21808d6e0 100644
--- a/src/client/views/DashboardView.tsx
+++ b/src/client/views/DashboardView.tsx
@@ -43,7 +43,7 @@ export class DashboardView extends React.Component {
     @observable private selectedDashboardGroup = DashboardGroup.MyDashboards;
 
     @observable private newDashboardName: string | undefined = undefined;
-    @observable private newDashboardColor: string | undefined = "#AFAFAF";
+    @observable private newDashboardColor: string | undefined = '#AFAFAF';
     @action abortCreateNewDashboard = () => {
         this.newDashboardName = undefined;
     };
@@ -100,30 +100,15 @@ export class DashboardView extends React.Component {
         const dashboardCount = DocListCast(Doc.MyDashboards.data).length + 1;
         const placeholder = `Dashboard ${dashboardCount}`;
         return (
-            <div className="new-dashboard"
-                style={{ 
+            <div
+                className="new-dashboard"
+                style={{
                     background: StrCast(Doc.UserDoc().userBackgroundColor),
-                    color: StrCast(Doc.UserDoc().userColor)
-                }}
-            >
+                    color: StrCast(Doc.UserDoc().userColor),
+                }}>
                 <div className="header">Create New Dashboard</div>
-                <EditableText 
-                    formLabel='Title'
-                    placeholder={placeholder}
-                    type={Type.SEC}
-                    color={StrCast(Doc.UserDoc().userColor)}
-                    setVal={val => this.setNewDashboardName(val as string)}
-                    fillWidth
-                />
-                <ColorPicker
-                    formLabel='Background'
-                    colorPickerType='github'
-                    type={Type.TERT}
-                    selectedColor={this.newDashboardColor}
-                    setSelectedColor={color => {
-                        this.setNewDashboardColor(color);
-                    }}
-                />
+                <EditableText formLabel="Title" placeholder={placeholder} type={Type.SEC} color={StrCast(Doc.UserDoc().userColor)} setVal={val => this.setNewDashboardName(val as string)} fillWidth />
+                <ColorPicker formLabel="Background" colorPickerType="github" type={Type.TERT} selectedColor={this.newDashboardColor} setSelectedColor={this.setNewDashboardColor} />
                 <div className="button-bar">
                     <Button text="Cancel" color={StrCast(Doc.UserDoc().userColor)} onClick={this.abortCreateNewDashboard} />
                     <Button type={Type.TERT} text="Create" color={StrCast(Doc.UserDoc().userVariantColor)} onClick={() => this.createNewDashboard(this.newDashboardName!, this.newDashboardColor)} />
@@ -165,21 +150,14 @@ export class DashboardView extends React.Component {
     };
 
     render() {
-        const color = StrCast(Doc.UserDoc().userColor)
-        const variant = StrCast(Doc.UserDoc().userVariantColor)
+        const color = StrCast(Doc.UserDoc().userColor);
+        const variant = StrCast(Doc.UserDoc().userVariantColor);
         return (
             <>
                 <div className="dashboard-view">
                     <div className="left-menu">
-                        <Button 
-                            text={'My Dashboards'}
-                            active={this.selectedDashboardGroup === DashboardGroup.MyDashboards}
-                            color={color}
-                            align={'flex-start'}
-                            onClick={() => this.selectDashboardGroup(DashboardGroup.MyDashboards)}
-                            fillWidth
-                        />
-                        <Button 
+                        <Button text={'My Dashboards'} active={this.selectedDashboardGroup === DashboardGroup.MyDashboards} color={color} align={'flex-start'} onClick={() => this.selectDashboardGroup(DashboardGroup.MyDashboards)} fillWidth />
+                        <Button
                             text={'Shared Dashboards' + ' (' + this.getDashboards(DashboardGroup.SharedDashboards).length + ')'}
                             active={this.selectedDashboardGroup === DashboardGroup.SharedDashboards}
                             color={this.getDashboards(DashboardGroup.SharedDashboards).some(dash => !DocListCast(Doc.MySharedDocs.viewed).includes(dash)) ? 'green' : color}
@@ -196,11 +174,11 @@ export class DashboardView extends React.Component {
                                 .filter(key => key !== `acl-${Doc.CurrentUserEmailNormalized}` && !['acl-Me', 'acl-Guest'].includes(key))
                                 .some(key => dashboard[DocAcl][key] !== AclPrivate);
                             return (
-                                <div 
-                                    className="dashboard-container" 
-                                    key={dashboard[Id]} 
+                                <div
+                                    className="dashboard-container"
+                                    key={dashboard[Id]}
                                     style={{ background: this.isUnviewedSharedDashboard(dashboard) && this.selectedDashboardGroup === DashboardGroup.SharedDashboards ? '#6CB982' : shared ? variant : '' }}
-                                    onContextMenu={e => this.onContextMenu(dashboard, e)} 
+                                    onContextMenu={e => this.onContextMenu(dashboard, e)}
                                     onClick={e => this.clickDashboard(e, dashboard)}>
                                     <img
                                         src={
@@ -208,12 +186,7 @@ export class DashboardView extends React.Component {
                                         }
                                     />
                                     <div className="info">
-                                        <EditableText 
-                                            type={Type.PRIM}
-                                            color={color}
-                                            val={StrCast(dashboard.title)} 
-                                            setVal={val => (Doc.GetProto(dashboard).title = val)}
-                                        />
+                                        <EditableText type={Type.PRIM} color={color} val={StrCast(dashboard.title)} setVal={val => (Doc.GetProto(dashboard).title = val)} />
                                         {this.selectedDashboardGroup === DashboardGroup.SharedDashboards && this.isUnviewedSharedDashboard(dashboard) ? <div>unviewed</div> : <div></div>}
                                         <div
                                             className="more"
@@ -229,10 +202,13 @@ export class DashboardView extends React.Component {
                                             <Button size={Size.SMALL} color={color} icon={<FontAwesomeIcon color={color} icon="bars" />} />
                                         </div>
                                     </div>
-                                    <div className={`background`} style={{
-                                        background: StrCast(Doc.UserDoc().userColor),
-                                        filter: 'opacity(0.2)'
-                                    }}/>
+                                    <div
+                                        className={`background`}
+                                        style={{
+                                            background: StrCast(Doc.UserDoc().userColor),
+                                            filter: 'opacity(0.2)',
+                                        }}
+                                    />
                                     <div className={'dashboard-status' + (shared ? '-shared' : '')}>{shared ? 'shared' : ''}</div>
                                 </div>
                             );
@@ -243,10 +219,13 @@ export class DashboardView extends React.Component {
                                 this.setNewDashboardName('');
                             }}>
                             +
-                            <div className={`background`} style={{
-                                background: StrCast(Doc.UserDoc().userColor),
-                                filter: 'opacity(0.2)'
-                            }}/>
+                            <div
+                                className={`background`}
+                                style={{
+                                    background: StrCast(Doc.UserDoc().userColor),
+                                    filter: 'opacity(0.2)',
+                                }}
+                            />
                         </div>
                     </div>
                 </div>
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index 8fe5c2e01..e076e69ca 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -3,7 +3,7 @@ import { DateField } from '../../fields/DateField';
 import { Doc, DocListCast, HierarchyMapping, Opt, ReverseHierarchyMap } from '../../fields/Doc';
 import { AclAdmin, AclAugment, AclEdit, AclPrivate, AclReadonly, DocAcl, DocData } from '../../fields/DocSymbols';
 import { List } from '../../fields/List';
-import { Cast, StrCast } from '../../fields/Types';
+import { Cast, DocCast, StrCast } from '../../fields/Types';
 import { distributeAcls, GetEffectiveAcl, inheritParentAcls, SharingPermissions } from '../../fields/util';
 import { returnFalse } from '../../Utils';
 import { DocUtils } from '../documents/Documents';
@@ -149,9 +149,9 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps>()
                 toRemove.forEach(doc => {
                     leavePushpin && DocUtils.LeavePushpin(doc, annotationKey ?? this.annotationKey);
                     Doc.RemoveDocFromList(targetDataDoc, annotationKey ?? this.annotationKey, doc);
+                    Doc.RemoveDocFromList(Doc.GetProto(doc), 'proto_embeddings', doc);
                     doc.embedContainer = undefined;
                     if (recent) {
-                        Doc.RemoveDocFromList(recent, 'data', doc);
                         doc.type !== DocumentType.LOADING && Doc.AddDocToList(recent, 'data', doc, undefined, true, true);
                     }
                 });
diff --git a/src/client/views/FilterPanel.tsx b/src/client/views/FilterPanel.tsx
index 68d29942b..63bd01b19 100644
--- a/src/client/views/FilterPanel.tsx
+++ b/src/client/views/FilterPanel.tsx
@@ -169,8 +169,6 @@ export class FilterPanel extends React.Component<filterProps> {
 
     render() {
         const options = this._allFacets.filter(facet => this.currentFacets.indexOf(facet) === -1).map(facet => ({ value: facet, label: facet }));
-        console.log("this is option " + options)
-        console.log("this is alll facets " + this._allFacets)
         return (
             <div className="filterBox-treeView">
                 <div className="filterBox-select">
@@ -192,17 +190,15 @@ export class FilterPanel extends React.Component<filterProps> {
                 <div className="filterBox-tree" key="tree">
                     {Array.from(this.activeFacets.keys()).map(facetHeader => (
                         <div>
-                            <div className  = "filterBox-facetHeader">
-                                <div className = "filterBox-facetHeader-Header"> </div>
+                            <div className="filterBox-facetHeader">
+                                <div className="filterBox-facetHeader-Header"> </div>
                                 {facetHeader.charAt(0).toUpperCase() + facetHeader.slice(1)}
-                                
-                                <div className = "filterBox-facetHeader-collapse"> 
-                                 <AiOutlineMinusSquare/>
-                                 {/* <CiCircleRemove/> */}
-                                  </div>
-                               
+
+                                <div className="filterBox-facetHeader-collapse">
+                                    <AiOutlineMinusSquare />
+                                    {/* <CiCircleRemove/> */}
+                                </div>
                             </div>
-                           
 
                             {this.displayFacetValueFilterUIs(this.activeFacets.get(facetHeader), facetHeader)}
                         </div>
diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx
index 286d39943..f79a30ad3 100644
--- a/src/client/views/LightboxView.tsx
+++ b/src/client/views/LightboxView.tsx
@@ -313,8 +313,10 @@ export class LightboxView extends React.Component<LightboxViewProps> {
                     className="lightboxView-tabBtn"
                     title="open in tab"
                     onClick={e => {
+                        const lightdoc = LightboxView._docTarget || LightboxView._doc!;
                         e.stopPropagation();
-                        CollectionDockingView.AddSplit(LightboxView._docTarget || LightboxView._doc!, OpenWhereMod.none);
+                        Doc.RemoveDocFromList(Doc.MyRecentlyClosed, 'data', lightdoc);
+                        CollectionDockingView.AddSplit(lightdoc, OpenWhereMod.none);
                         SelectionManager.DeselectAll();
                         LightboxView.SetLightboxDoc(undefined);
                     }}>
diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx
index 2fa42d091..2a73d77ed 100644
--- a/src/client/views/Main.tsx
+++ b/src/client/views/Main.tsx
@@ -6,10 +6,7 @@ import * as React from 'react';
 import * as ReactDOM from 'react-dom/client';
 import { AssignAllExtensions } from '../../extensions/General/Extensions';
 import { FieldLoader } from '../../fields/FieldLoader';
-import { DocServer } from '../DocServer';
-import { Docs } from '../documents/Documents';
 import { CurrentUserUtils } from '../util/CurrentUserUtils';
-import { LinkManager } from '../util/LinkManager'; // this must come before importing Docs and CurrentUserUtils
 import { ReplayMovements } from '../util/ReplayMovements';
 import { TrackMovements } from '../util/TrackMovements';
 import { CollectionView } from './collections/CollectionView';
@@ -20,7 +17,7 @@ import './global/globalScripts';
 dotenv.config();
 
 AssignAllExtensions();
-FieldLoader.ServerLoadStatus = { requested: 0, retrieved: 0 }; // bcz: not sure why this is needed to get the code loaded properly...
+FieldLoader.ServerLoadStatus = { requested: 0, retrieved: 0, message: 'cache' }; // bcz: not sure why this is needed to get the code loaded properly...
 
 (async () => {
     MainView.Live = window.location.search.includes('live');
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index cbaa763f5..dc236b603 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -4,7 +4,7 @@ import * as far from '@fortawesome/free-regular-svg-icons';
 import * as fa from '@fortawesome/free-solid-svg-icons';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import 'browndash-components/dist/styles/global.min.css';
-import { action, computed, configure, observable, reaction, runInAction } from 'mobx';
+import { action, computed, configure, observable, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
 import 'normalize.css';
 import * as React from 'react';
@@ -182,14 +182,6 @@ export class MainView extends React.Component {
                 'currentFrame',
             ]); // can play with these fields on someone else's
         }
-        DocServer.GetRefField('rtfProto').then(
-            proto =>
-                proto instanceof Doc &&
-                reaction(
-                    () => StrCast(proto.BROADCAST_MESSAGE),
-                    msg => msg && alert(msg)
-                )
-        );
 
         const tag = document.createElement('script');
         tag.src = 'https://www.youtube.com/iframe_api';
@@ -527,7 +519,7 @@ export class MainView extends React.Component {
     });
 
     initEventListeners = () => {
-        window.addEventListener('beforeunload', () => DocServer.UPDATE_SERVER_CACHE());
+        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));
diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx
index b74eabcc3..8cae34d7d 100644
--- a/src/client/views/PropertiesButtons.tsx
+++ b/src/client/views/PropertiesButtons.tsx
@@ -375,7 +375,6 @@ export class PropertiesButtons extends React.Component<{}, {}> {
                 val: value[1],
             };
         });
-        console.log('click val: ', this.onClickVal);
         return !this.selectedDoc ? null : (
             <Dropdown
                 tooltip={'Choose onClick behavior'}
diff --git a/src/client/views/PropertiesDocContextSelector.tsx b/src/client/views/PropertiesDocContextSelector.tsx
index 395aa2b61..d157e7b1c 100644
--- a/src/client/views/PropertiesDocContextSelector.tsx
+++ b/src/client/views/PropertiesDocContextSelector.tsx
@@ -38,7 +38,6 @@ export class PropertiesDocContextSelector extends React.Component<PropertiesDocC
                 }, new Set<Doc>())
                 .keys()
         );
-        console.log('embeddings ' + embeddings.length);
 
         return doclayouts
             .filter(doc => !Doc.AreProtosEqual(doc, CollectionDockingView.Instance?.props.Document))
diff --git a/src/client/views/PropertiesSection.tsx b/src/client/views/PropertiesSection.tsx
index ec8043ffe..6fab0168b 100644
--- a/src/client/views/PropertiesSection.tsx
+++ b/src/client/views/PropertiesSection.tsx
@@ -1,19 +1,19 @@
 import React = require('react');
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
-import { action, computed, observable } from "mobx"
-import { observer } from "mobx-react"
-import './PropertiesSection.scss'
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { action, computed, observable } from 'mobx';
+import { observer } from 'mobx-react';
+import './PropertiesSection.scss';
 import { Doc } from '../../fields/Doc';
 import { StrCast } from '../../fields/Types';
 
 export interface PropertiesSectionProps {
-    title: string, 
-    content?: JSX.Element | string | null, 
-    isOpen: boolean,
-    setIsOpen: (bool: boolean) => any 
-    inSection?: boolean,
-    setInSection?: (bool: boolean) => any
-    onDoubleClick?: () => void
+    title: string;
+    content?: JSX.Element | string | null;
+    isOpen: boolean;
+    setIsOpen: (bool: boolean) => any;
+    inSection?: boolean;
+    setInSection?: (bool: boolean) => any;
+    onDoubleClick?: () => void;
 }
 
 @observer
@@ -33,34 +33,32 @@ export class PropertiesSection extends React.Component<PropertiesSectionProps> {
     @observable isDouble: boolean = false;
 
     render() {
-        console.log(this.props.title, this.props.content)
-        if (this.props.content === undefined || this.props.content === null) return null
-        else return <div className="propertiesView-section" onPointerEnter={action(() => (this.props.setInSection && this.props.setInSection(true)))} onPointerLeave={action(() => (this.props.setInSection && this.props.setInSection(false)))}>
-        <div className="propertiesView-sectionTitle" 
-            onDoubleClick={action((e) => {
-                this.isDouble = true;
-                this.props.onDoubleClick && this.props.onDoubleClick()
-                console.log("open options")
-                this.props.setIsOpen(true)
-                setTimeout(() => this.isDouble = false, 300)
-            })}
-            onClick={action((e) => {
-                this.props.setIsOpen(!this.props.isOpen)
-            })} 
-            style={{ 
-                background: this.props.isOpen ?  this.variantColor : this.backgroundColor,
-                color: this.color
-            }}>
-            {this.props.title}
-            <div className="propertiesView-sectionTitle-icon">
-                <FontAwesomeIcon icon={this.props.isOpen ? 'caret-down' : 'caret-right'} size="lg"  />
-            </div>
-        </div>
-        {!this.props.isOpen ? null :
-            <div className="propertiesView-content">
-                {this.props.content}
-            </div>
-        }
-    </div>
+        if (this.props.content === undefined || this.props.content === null) return null;
+        else
+            return (
+                <div className="propertiesView-section" onPointerEnter={action(() => this.props.setInSection && this.props.setInSection(true))} onPointerLeave={action(() => this.props.setInSection && this.props.setInSection(false))}>
+                    <div
+                        className="propertiesView-sectionTitle"
+                        onDoubleClick={action(e => {
+                            this.isDouble = true;
+                            this.props.onDoubleClick && this.props.onDoubleClick();
+                            this.props.setIsOpen(true);
+                            setTimeout(() => (this.isDouble = false), 300);
+                        })}
+                        onClick={action(e => {
+                            this.props.setIsOpen(!this.props.isOpen);
+                        })}
+                        style={{
+                            background: this.props.isOpen ? this.variantColor : this.backgroundColor,
+                            color: this.color,
+                        }}>
+                        {this.props.title}
+                        <div className="propertiesView-sectionTitle-icon">
+                            <FontAwesomeIcon icon={this.props.isOpen ? 'caret-down' : 'caret-right'} size="lg" />
+                        </div>
+                    </div>
+                    {!this.props.isOpen ? null : <div className="propertiesView-content">{this.props.content}</div>}
+                </div>
+            );
     }
-}
\ No newline at end of file
+}
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 27b9c3c7a..872f1c6ab 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -8,7 +8,7 @@ import { concat } from 'lodash';
 import { Lambda, action, computed, observable } from 'mobx';
 import { observer } from 'mobx-react';
 import { ColorState, SketchPicker } from 'react-color';
-import * as Icons from "react-icons/bs"; //{BsCollectionFill, BsFillFileEarmarkImageFill} from "react-icons/bs"
+import * as Icons from 'react-icons/bs'; //{BsCollectionFill, BsFillFileEarmarkImageFill} from "react-icons/bs"
 import { GrCircleInformation } from 'react-icons/gr';
 import { Utils, emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, setupMoveUpEvents } from '../../Utils';
 import { Doc, DocListCast, Field, FieldResult, HierarchyMapping, NumListCast, Opt, ReverseHierarchyMap, StrListCast } from '../../fields/Doc';
@@ -51,7 +51,6 @@ interface PropertiesViewProps {
     addDocTab: (doc: Doc, where: OpenWhere) => boolean;
 }
 
-
 @observer
 export class PropertiesView extends React.Component<PropertiesViewProps> {
     private _widthUndo?: UndoManager.Batch;
@@ -191,7 +190,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
             });
 
             rows.push(
-                <div className="propertiesView-field" key="newKeyValue" style={{ marginTop: '3px', backgroundColor: "white", textAlign: "center" }}>
+                <div className="propertiesView-field" key="newKeyValue" style={{ marginTop: '3px', backgroundColor: 'white', textAlign: 'center' }}>
                     <EditableView key="editableView" oneLine contents={'add key:value or #tags'} height={13} fontSize={10} GetValue={() => ''} SetValue={this.setKeyValue} />
                 </div>
             );
@@ -249,14 +248,12 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         return !this.selectedDoc ? null : <PropertiesDocContextSelector DocView={this.selectedDocumentView} hideTitle={true} addDocTab={this.props.addDocTab} />;
     }
 
-    @computed get contextCount(){
-        console.log("in context count");
-        if (this.selectedDocumentView){ 
-            const target = (this.selectedDocumentView.props.Document)
-            const embeddings = DocListCast(target.proto_embeddings)
-            console.log(embeddings.length -1 );
-            return (embeddings.length - 1)
-        } else{
+    @computed get contextCount() {
+        if (this.selectedDocumentView) {
+            const target = this.selectedDocumentView.props.Document;
+            const embeddings = DocListCast(target.proto_embeddings);
+            return embeddings.length - 1;
+        } else {
             return 0;
         }
     }
@@ -266,13 +263,11 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         return !selAnchor ? null : <PropertiesDocBacklinksSelector Document={selAnchor} hideTitle={true} addDocTab={this.props.addDocTab} />;
     }
 
-    @computed get linkCount(){
-        const selAnchor =  this.selectedDocumentView?.anchorViewDoc ?? LinkManager.currentLinkAnchor ?? this.selectedDoc;
+    @computed get linkCount() {
+        const selAnchor = this.selectedDocumentView?.anchorViewDoc ?? LinkManager.currentLinkAnchor ?? this.selectedDoc;
         var counter = 0;
 
-        LinkManager.Links(selAnchor).forEach((l, i) =>
-                counter ++
-            );
+        LinkManager.Links(selAnchor).forEach((l, i) => counter++);
 
         return counter;
     }
@@ -356,7 +351,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         return (
             <Tooltip title={<div className="dash-tooltip">Notify with message</div>}>
                 <div className="notify-button">
-                    <FontAwesomeIcon className="notify-button-icon" icon="bell"  size="sm" />
+                    <FontAwesomeIcon className="notify-button-icon" icon="bell" size="sm" />
                 </div>
             </Tooltip>
         );
@@ -367,16 +362,16 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
      */
     @computed get expansionIcon() {
         return (
-            <div className="expansion-button" >
-                <IconButton 
-                    icon={<FontAwesomeIcon icon={'ellipsis-h'} />} 
-                    size={Size.XSMALL} 
-                    color={StrCast(Doc.UserDoc().userColor)} 
+            <div className="expansion-button">
+                <IconButton
+                    icon={<FontAwesomeIcon icon={'ellipsis-h'} />}
+                    size={Size.XSMALL}
+                    color={StrCast(Doc.UserDoc().userColor)}
                     onClick={action(() => {
                         if (this.selectedDocumentView || this.selectedDoc) {
                             SharingManager.Instance.open(this.selectedDocumentView?.props.Document === this.selectedDoc ? this.selectedDocumentView : undefined, this.selectedDoc);
                         }
-                    })} 
+                    })}
                 />
             </div>
         );
@@ -418,7 +413,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
             <div>
                 <div className={'propertiesView-shareDropDown'}>
                     <div className={`propertiesView-shareDropDown${permission}`}>
-                        <div >{admin && permission !== 'Owner' ? this.getPermissionsSelect(name, permission, showGuestOptions) : concat(shareImage, ' ', permission)}</div>
+                        <div>{admin && permission !== 'Owner' ? this.getPermissionsSelect(name, permission, showGuestOptions) : concat(shareImage, ' ', permission)}</div>
                     </div>
                 </div>
             </div>
@@ -450,7 +445,6 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         const target = docs[0];
 
         const showAdmin = GetEffectiveAcl(target) == AclAdmin;
-        console.log(GetEffectiveAcl(target), Doc.GetProto(target)[`acl-${normalizeEmail(Doc.CurrentUserEmail)}`])
         const individualTableEntries = [];
         const usersAdded: string[] = []; // all shared users being added - organized by denormalized email
 
@@ -522,7 +516,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: StrCast(Doc.UserDoc().userBackgroundColor), color: StrCast(Doc.UserDoc().userColor) }}>
                     {<div> {individualTableEntries}</div>}
                 </div>
                 {groupTableEntries.length > 0 ? (
@@ -530,7 +524,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: StrCast(Doc.UserDoc().userBackgroundColor), color: StrCast(Doc.UserDoc().userColor) }}>
                             {<div> {groupTableEntries}</div>}
                         </div>
                     </div>
@@ -562,68 +556,43 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     }
 
     @computed get editableTitle() {
-
         const titles = new Set<string>();
         const title = Array.from(titles.keys()).length > 1 ? '--multiple selected--' : StrCast(this.selectedDoc?.title);
         SelectionManager.Views().forEach(dv => titles.add(StrCast(dv.rootDoc.title)));
-        return (
-            <EditableText
-                val={title}
-                setVal={this.setTitle}
-                color={this.color}
-                type={Type.SEC}
-                formLabel={"Title"}
-                fillWidth
-            />
-        );
+        return <EditableText val={title} setVal={this.setTitle} color={this.color} type={Type.SEC} formLabel={'Title'} fillWidth />;
     }
 
     @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);
- 
-         return (
-             <div>
-                 <div className = "propertiesView-wordType">Type</div>  
-                 <div className= "currentType"> 
-                 <div className='currentType-icon'>
-                      {this.currentComponent}
-                 </div>
-                
-                   {capitalizedDocType} 
-                
-                 </div>
-                
-             </div>
-           
-         )
-     }
+        const documentType = StrCast(this.selectedDoc?.type);
+        var currentType: string = documentType;
+        var capitalizedDocType = Utils.cleanDocumentType(currentType as DocumentType);
 
-    @computed get currentComponent() {
+        return (
+            <div>
+                <div className="propertiesView-wordType">Type</div>
+                <div className="currentType">
+                    <div className="currentType-icon">{this.currentComponent}</div>
 
-        var iconName = StrCast(this.selectedDoc?.systemIcon)
+                    {capitalizedDocType}
+                </div>
+            </div>
+        );
+    }
 
-        // if (this.selectedDoc?.type === DocumentType.COL){
-        //     console.log("i did it!")
-        // }
-       
+    @computed get currentComponent() {
+        var iconName = StrCast(this.selectedDoc?.systemIcon);
 
-        if (iconName){
+        if (iconName) {
             const Icon = Icons[iconName as keyof typeof Icons];
             return <Icon />;
-        } else{
-          return <Icons.BsFillCollectionFill/>
-
+        } else {
+            return <Icons.BsFillCollectionFill />;
         }
     }
 
     @undoBatch
     @action
     setTitle = (value: string | number) => {
-        console.log(value)
         if (SelectionManager.Views().length > 1) {
             SelectionManager.Views().map(dv => Doc.SetInPlace(dv.rootDoc, 'title', value, true));
         } else if (this.dataDoc) {
@@ -687,7 +656,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                         className="inking-button-points"
                         style={{ backgroundColor: InkStrokeProperties.Instance._controlButton ? 'black' : '' }}
                         onPointerDown={action(() => (InkStrokeProperties.Instance._controlButton = !InkStrokeProperties.Instance._controlButton))}>
-                        <FontAwesomeIcon icon="bezier-curve"  size="lg" />
+                        <FontAwesomeIcon icon="bezier-curve" size="lg" />
                     </div>
                 </Tooltip>
             </div>
@@ -706,10 +675,10 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                 <input className="inputBox-input" type="text" value={value} onChange={e => setter(e.target.value)} onKeyPress={e => e.stopPropagation()} />
                 <div className="inputBox-button">
                     <div className="inputBox-button-up" key="up2" onPointerDown={undoBatch(action(() => this.upDownButtons('up', key)))}>
-                        <FontAwesomeIcon icon="caret-up"  size="sm" />
+                        <FontAwesomeIcon icon="caret-up" size="sm" />
                     </div>
                     <div className="inputbox-Button-down" key="down2" onPointerDown={undoBatch(action(() => this.upDownButtons('down', key)))}>
-                        <FontAwesomeIcon icon="caret-down"  size="sm" />
+                        <FontAwesomeIcon icon="caret-down" size="sm" />
                     </div>
                 </div>
             </div>
@@ -963,10 +932,10 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                 <input className="inputBox-input" type="text" value={value} onChange={e => setter(e.target.value)} />
                 <div className="inputBox-button">
                     <div className="inputBox-button-up" key="up2" onPointerDown={undoBatch(action(() => this.upDownButtons('up', key)))}>
-                        <FontAwesomeIcon icon="caret-up"  size="sm" />
+                        <FontAwesomeIcon icon="caret-up" size="sm" />
                     </div>
                     <div className="inputbox-Button-down" key="down2" onPointerDown={undoBatch(action(() => this.upDownButtons('down', key)))}>
-                        <FontAwesomeIcon icon="caret-down"  size="sm" />
+                        <FontAwesomeIcon icon="caret-down" size="sm" />
                     </div>
                 </div>
             </div>
@@ -983,7 +952,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         this.openSharing = false;
         this.openLayout = false;
         this.openFilters = false;
-    }
+    };
 
     @computed get widthAndDash() {
         return (
@@ -1065,64 +1034,45 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     }
 
     getNumber = (label: string, unit: string, min: number, max: number, number: number, setNumber: any) => {
-        return <div>
-            <NumberInput
-                formLabel={label}
-                formLabelPlacement={'left'}
-                type={Type.SEC}
-                unit={unit}
-                fillWidth
-                color={this.color}
-                number={number}
-                setNumber={setNumber} 
-                min={min}
-                max={max}            
-            />
-            <Slider 
-                multithumb={false}
-                color={this.color}
-                size={Size.XSMALL} 
-                min={min} 
-                max={max}
-                unit={unit} 
-                number={number}
-                setNumber={setNumber}
-                fillWidth
-            />
-        </div>
-    }
+        return (
+            <div>
+                <NumberInput formLabel={label} formLabelPlacement={'left'} type={Type.SEC} unit={unit} fillWidth color={this.color} number={number} setNumber={setNumber} min={min} max={max} />
+                <Slider multithumb={false} color={this.color} size={Size.XSMALL} min={min} max={max} unit={unit} number={number} setNumber={setNumber} fillWidth />
+            </div>
+        );
+    };
 
     @computed get transformEditor() {
         return (
             <div className="transform-editor">
                 {this.isInk ? this.controlPointsButton : null}
                 {this.getNumber(
-                    "Height",
-                    " px",
+                    'Height',
+                    ' px',
                     0,
                     1000,
                     Number(this.shapeHgt),
                     undoable((val: string) => !isNaN(Number(val)) && (this.shapeHgt = val), 'set height')
                 )}
                 {this.getNumber(
-                    "Width",
-                    " px",
+                    'Width',
+                    ' px',
                     0,
                     1000,
                     Number(this.shapeWid),
                     undoable((val: string) => !isNaN(Number(val)) && (this.shapeWid = val), 'set width')
                 )}
                 {this.getNumber(
-                    "X Coordinate",
-                    " px",
+                    'X Coordinate',
+                    ' px',
                     -2000,
                     2000,
                     Number(this.shapeXps),
                     undoable((val: string) => !isNaN(Number(val)) && (this.shapeXps = val), 'set x coord')
                 )}
                 {this.getNumber(
-                    "Y Coordinate",
-                    " px",
+                    'Y Coordinate',
+                    ' px',
                     -2000,
                     2000,
                     Number(this.shapeYps),
@@ -1133,38 +1083,44 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     }
 
     @computed get optionsSubMenu() {
-        return <PropertiesSection
-            title="Options"
-            content={<PropertiesButtons />}
-            inSection={this.inOptions}
-            isOpen={this.openOptions}
-            setInSection={(bool) => this.inOptions = bool}
-            setIsOpen={(bool) => this.openOptions = bool}
-            onDoubleClick={() => this.onDoubleClick()}
-        />
+        return (
+            <PropertiesSection
+                title="Options"
+                content={<PropertiesButtons />}
+                inSection={this.inOptions}
+                isOpen={this.openOptions}
+                setInSection={bool => (this.inOptions = bool)}
+                setIsOpen={bool => (this.openOptions = bool)}
+                onDoubleClick={() => this.onDoubleClick()}
+            />
+        );
     }
 
     @computed get sharingSubMenu() {
-        return <PropertiesSection
-            title="Sharing & Permissions"
-            content={<>
-            {/* <div className="propertiesView-buttonContainer"> */}
-                    <div className="propertiesView-acls-checkbox">
-                        Layout Permissions
-                        <Checkbox color="primary" onChange={action(() => (this.layoutDocAcls = !this.layoutDocAcls))} checked={this.layoutDocAcls} />
-                    </div>
-                    {/* <Tooltip title={<><div className="dash-tooltip">{"Re-distribute sharing settings"}</div></>}>
+        return (
+            <PropertiesSection
+                title="Sharing & Permissions"
+                content={
+                    <>
+                        {/* <div className="propertiesView-buttonContainer"> */}
+                        <div className="propertiesView-acls-checkbox">
+                            Layout Permissions
+                            <Checkbox color="primary" onChange={action(() => (this.layoutDocAcls = !this.layoutDocAcls))} checked={this.layoutDocAcls} />
+                        </div>
+                        {/* <Tooltip title={<><div className="dash-tooltip">{"Re-distribute sharing settings"}</div></>}>
                         <button onPointerDown={() => SharingManager.Instance.distributeOverCollection(this.selectedDoc!)}>
                             <FontAwesomeIcon icon="redo-alt"  size="1x" />
                         </button>
                     </Tooltip> */}
-                {/* </div> */}
-                {this.sharingTable}
-            </>}
-            isOpen={this.openSharing}
-            setIsOpen={(bool) => this.openSharing = bool}
-            onDoubleClick={() => this.onDoubleClick()}
-        />
+                        {/* </div> */}
+                        {this.sharingTable}
+                    </>
+                }
+                isOpen={this.openSharing}
+                setIsOpen={bool => (this.openSharing = bool)}
+                onDoubleClick={() => this.onDoubleClick()}
+            />
+        );
     }
 
     /**
@@ -1192,15 +1148,19 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     };
 
     @computed get filtersSubMenu() {
-        return <PropertiesSection 
-            title="Filters"
-            content={<div className="propertiesView-content filters" style={{ position: 'relative', height: 'auto' }}>
-                <FilterPanel rootDoc={this.selectedDoc ?? Doc.ActiveDashboard!} />
-            </div>}
-            isOpen={this.openFilters}
-            setIsOpen={(bool) => this.openFilters = bool}
-             onDoubleClick={() => this.onDoubleClick()}
-        />
+        return (
+            <PropertiesSection
+                title="Filters"
+                content={
+                    <div className="propertiesView-content filters" style={{ position: 'relative', height: 'auto' }}>
+                        <FilterPanel rootDoc={this.selectedDoc ?? Doc.ActiveDashboard!} />
+                    </div>
+                }
+                isOpen={this.openFilters}
+                setIsOpen={bool => (this.openFilters = bool)}
+                onDoubleClick={() => this.onDoubleClick()}
+            />
+        );
     }
 
     @computed get inkSubMenu() {
@@ -1208,68 +1168,42 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
 
         return (
             <>
-                <PropertiesSection
-                    title="Appearance"
-                    content={this.isInk ? this.appearanceEditor : null}
-                    isOpen={this.openAppearance}
-                    setIsOpen={(bool) => this.openAppearance = bool}
-                     onDoubleClick={() => this.onDoubleClick()}
-                />
-                <PropertiesSection
-                    title="Transform"
-                    content={this.transformEditor}
-                    isOpen={this.openTransform}
-                    setIsOpen={(bool) => this.openTransform = bool}
-                    onDoubleClick={() => this.onDoubleClick()}
-                />
+                <PropertiesSection title="Appearance" content={this.isInk ? this.appearanceEditor : null} isOpen={this.openAppearance} setIsOpen={bool => (this.openAppearance = bool)} onDoubleClick={() => this.onDoubleClick()} />
+                <PropertiesSection title="Transform" content={this.transformEditor} isOpen={this.openTransform} setIsOpen={bool => (this.openTransform = bool)} onDoubleClick={() => this.onDoubleClick()} />
             </>
         );
     }
 
     @computed get fieldsSubMenu() {
-        return <PropertiesSection
-            title="Fields & Tags"
-            content={<div className="propertiesView-content fields">{
-                Doc.noviceMode ? this.noviceFields : this.expandedField}
-            </div>}
-            isOpen={this.openFields}
-            setIsOpen={(bool) => this.openFields = bool}
-            onDoubleClick={() => this.onDoubleClick()}
-        />
+        return (
+            <PropertiesSection
+                title="Fields & Tags"
+                content={<div className="propertiesView-content fields">{Doc.noviceMode ? this.noviceFields : this.expandedField}</div>}
+                isOpen={this.openFields}
+                setIsOpen={bool => (this.openFields = bool)}
+                onDoubleClick={() => this.onDoubleClick()}
+            />
+        );
     }
 
     @computed get contextsSubMenu() {
-        return <PropertiesSection
-            title="Other Contexts"
-            content={this.contextCount > 0 ? this.contexts : "There are no other contexts."}
-            isOpen={this.openContexts}
-            setIsOpen={(bool) => this.openContexts = bool}
-            onDoubleClick={() => this.onDoubleClick()}
-        />
+        return (
+            <PropertiesSection
+                title="Other Contexts"
+                content={this.contextCount > 0 ? this.contexts : 'There are no other contexts.'}
+                isOpen={this.openContexts}
+                setIsOpen={bool => (this.openContexts = bool)}
+                onDoubleClick={() => this.onDoubleClick()}
+            />
+        );
     }
 
-
-
-
-
     @computed get linksSubMenu() {
-        return <PropertiesSection
-            title="Linked To"
-            content={this.linkCount > 0 ? this.links : "There are no current links." }
-            isOpen={this.openLinks}
-            setIsOpen={(bool) => this.openLinks = bool}
-            onDoubleClick={() => this.onDoubleClick()}
-        />
+        return <PropertiesSection title="Linked To" content={this.linkCount > 0 ? this.links : 'There are no current links.'} isOpen={this.openLinks} setIsOpen={bool => (this.openLinks = bool)} onDoubleClick={() => this.onDoubleClick()} />;
     }
 
     @computed get layoutSubMenu() {
-        return <PropertiesSection
-            title="Layout"
-            content={this.layoutPreview}
-            isOpen={this.openLayout}
-            setIsOpen={(bool) => this.openLayout = bool}
-            onDoubleClick={() => this.onDoubleClick()}
-        />
+        return <PropertiesSection title="Layout" content={this.layoutPreview} isOpen={this.openLayout} setIsOpen={bool => (this.openLayout = bool)} onDoubleClick={() => this.onDoubleClick()} />;
     }
 
     @computed get description() {
@@ -1470,224 +1404,226 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         if (scale > 1) scale = 1;
         this.sourceAnchor && (this.sourceAnchor.followLinkZoomScale = scale);
     };
-    
+
     @computed get linkProperties() {
         const zoom = Number((NumCast(this.sourceAnchor?.followLinkZoomScale, 1) * 100).toPrecision(3));
         const targZoom = this.sourceAnchor?.followLinkZoom;
         const indent = 30;
         const hasSelectedAnchor = LinkManager.Links(this.sourceAnchor).includes(LinkManager.currentLink!);
 
-        return <>
-        <div className="propertiesView-section" style={{ background: 'darkgray' }}>
-            <div className="propertiesView-input first" style={{ display: 'grid', gridTemplateColumns: '84px auto' }}>
-                <p>Relationship</p>
-                {this.editRelationship}
-            </div>
-            <div className="propertiesView-input" style={{ display: 'grid', gridTemplateColumns: '84px auto' }}>
-                <p>Description</p>
-                {this.editDescription}
-            </div>
-            <div className="propertiesView-input inline">
-                <p>Show link</p>
-                <button
-                    style={{ background: !LinkManager.currentLink?.link_displayLine ? '' : '#4476f7', borderRadius: 3 }}
-                    onPointerDown={e => this.toggleLinkProp(e, 'link_displayLine')}
-                    onClick={e => e.stopPropagation()}
-                    className="propertiesButton">
-                    <FontAwesomeIcon className="fa-icon" icon={faArrowRight as IconLookup} size="lg" />
-                </button>
-            </div>
-            <div className="propertiesView-input inline" style={{ marginLeft: 10 }}>
-                <p>Auto-move anchors</p>
-                <button
-                    style={{ background: !LinkManager.currentLink?.link_autoMoveAnchors ? '' : '#4476f7', borderRadius: 3 }}
-                    onPointerDown={e => this.toggleLinkProp(e, 'link_autoMoveAnchors')}
-                    onClick={e => e.stopPropagation()}
-                    className="propertiesButton">
-                    <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
-                </button>
-            </div>
-            <div className="propertiesView-input inline" style={{ marginLeft: 10 }}>
-                <p>Display arrow</p>
-                <button
-                    style={{ background: !LinkManager.currentLink?.link_displayArrow ? '' : '#4476f7', borderRadius: 3 }}
-                    onPointerDown={e => this.toggleLinkProp(e, 'link_displayArrow')}
-                    onClick={e => e.stopPropagation()}
-                    className="propertiesButton">
-                    <FontAwesomeIcon className="fa-icon" icon={faArrowRight as IconLookup} size="lg" />
-                </button>
-            </div>
-        </div>
-        {!hasSelectedAnchor ? null : (
-            <div className="propertiesView-section">
-                <div className="propertiesView-input inline first" style={{ display: 'grid', gridTemplateColumns: '84px calc(100% - 84px)' }}>
-                    <p>Follow by</p>
-                    <select onChange={e => this.changeFollowBehavior(e.currentTarget.value === 'Default' ? undefined : e.currentTarget.value)} value={Cast(this.sourceAnchor?.followLinkLocation, 'string', null)}>
-                        <option value={undefined}>Default</option>
-                        <option value={OpenWhere.addLeft}>Opening in new left pane</option>
-                        <option value={OpenWhere.addRight}>Opening in new right pane</option>
-                        <option value={OpenWhere.replaceLeft}>Replacing left tab</option>
-                        <option value={OpenWhere.replaceRight}>Replacing right tab</option>
-                        <option value={OpenWhere.lightbox}>Opening in lightbox</option>
-                        <option value={OpenWhere.add}>Opening in new tab</option>
-                        <option value={OpenWhere.replace}>Replacing current tab</option>
-                        <option value={OpenWhere.inParent}>Opening in same collection</option>
-                        {LinkManager.currentLink?.linksToAnnotation ? <option value="openExternal">Open in external page</option> : null}
-                    </select>
-                </div>
-                <div className="propertiesView-input inline first" style={{ display: 'grid', gridTemplateColumns: '84px calc(100% - 134px) 50px' }}>
-                    <p>Animation</p>
-                    <select style={{ width: '100%', gridColumn: 2 }} onChange={e => this.changeAnimationBehavior(e.currentTarget.value)} value={StrCast(this.sourceAnchor?.followLinkAnimEffect, 'default')}>
-                        <option value="default">Default</option>
-                        {[PresEffect.None, PresEffect.Zoom, PresEffect.Lightspeed, PresEffect.Fade, PresEffect.Flip, PresEffect.Rotate, PresEffect.Bounce, PresEffect.Roll].map(effect => (
-                            <option key={effect.toString()} value={effect.toString()}>
-                                {effect.toString()}
-                            </option>
-                        ))}
-                    </select>
-                    <div className="effectDirection" style={{ marginLeft: '10px', display: 'grid', width: 40, height: 36, gridColumn: 3, gridTemplateRows: '12px 12px 12px' }}>
-                        {this.animationDirection(PresEffectDirection.Left, 'angle-right', 1, 2, {})}
-                        {this.animationDirection(PresEffectDirection.Right, 'angle-left', 3, 2, {})}
-                        {this.animationDirection(PresEffectDirection.Top, 'angle-down', 2, 1, {})}
-                        {this.animationDirection(PresEffectDirection.Bottom, 'angle-up', 2, 3, {})}
-                        {this.animationDirection(PresEffectDirection.Center, '', 2, 2, { width: 10, height: 10, alignSelf: 'center' })}
+        return (
+            <>
+                <div className="propertiesView-section" style={{ background: 'darkgray' }}>
+                    <div className="propertiesView-input first" style={{ display: 'grid', gridTemplateColumns: '84px auto' }}>
+                        <p>Relationship</p>
+                        {this.editRelationship}
+                    </div>
+                    <div className="propertiesView-input" style={{ display: 'grid', gridTemplateColumns: '84px auto' }}>
+                        <p>Description</p>
+                        {this.editDescription}
+                    </div>
+                    <div className="propertiesView-input inline">
+                        <p>Show link</p>
+                        <button
+                            style={{ background: !LinkManager.currentLink?.link_displayLine ? '' : '#4476f7', borderRadius: 3 }}
+                            onPointerDown={e => this.toggleLinkProp(e, 'link_displayLine')}
+                            onClick={e => e.stopPropagation()}
+                            className="propertiesButton">
+                            <FontAwesomeIcon className="fa-icon" icon={faArrowRight as IconLookup} size="lg" />
+                        </button>
+                    </div>
+                    <div className="propertiesView-input inline" style={{ marginLeft: 10 }}>
+                        <p>Auto-move anchors</p>
+                        <button
+                            style={{ background: !LinkManager.currentLink?.link_autoMoveAnchors ? '' : '#4476f7', borderRadius: 3 }}
+                            onPointerDown={e => this.toggleLinkProp(e, 'link_autoMoveAnchors')}
+                            onClick={e => e.stopPropagation()}
+                            className="propertiesButton">
+                            <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
+                        </button>
+                    </div>
+                    <div className="propertiesView-input inline" style={{ marginLeft: 10 }}>
+                        <p>Display arrow</p>
+                        <button
+                            style={{ background: !LinkManager.currentLink?.link_displayArrow ? '' : '#4476f7', borderRadius: 3 }}
+                            onPointerDown={e => this.toggleLinkProp(e, 'link_displayArrow')}
+                            onClick={e => e.stopPropagation()}
+                            className="propertiesButton">
+                            <FontAwesomeIcon className="fa-icon" icon={faArrowRight as IconLookup} size="lg" />
+                        </button>
                     </div>
                 </div>
-                {PresBox.inputter(
-                    '0.1',
-                    '0.1',
-                    '10',
-                    NumCast(this.sourceAnchor?.followLinkTransitionTime) / 1000,
-                    true,
-                    (val: string) => PresBox.SetTransitionTime(val, (timeInMS: number) => this.sourceAnchor && (this.sourceAnchor.followLinkTransitionTime = timeInMS)),
-                    indent
-                )}{' '}
-                <div
-                    className={'slider-headers'}
-                    style={{
-                        display: 'grid',
-                        justifyContent: 'space-between',
-                        width: `calc(100% - ${indent * 2}px)`,
-                        marginLeft: indent,
-                        marginRight: indent,
-                        gridTemplateColumns: 'auto auto',
-                        borderTop: 'solid',
-                    }}>
-                    <div className="slider-text">Fast</div>
-                    <div className="slider-text">Slow</div>
-                </div>{' '}
-                <div className="propertiesView-input inline">
-                    <p>Play Target Audio</p>
-                    <button
-                        style={{ background: !this.sourceAnchor?.followLinkAudio ? '' : '#4476f7', borderRadius: 3 }}
-                        onPointerDown={e => this.toggleAnchorProp(e, 'followLinkAudio', this.sourceAnchor)}
-                        onClick={e => e.stopPropagation()}
-                        className="propertiesButton">
-                        <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
-                    </button>
-                </div>
-                <div className="propertiesView-input inline">
-                    <p>Zoom Text Selections</p>
-                    <button
-                        style={{ background: !this.sourceAnchor?.followLinkZoomText ? '' : '#4476f7', borderRadius: 3 }}
-                        onPointerDown={e => this.toggleAnchorProp(e, 'followLinkZoomText', this.sourceAnchor)}
-                        onClick={e => e.stopPropagation()}
-                        className="propertiesButton">
-                        <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
-                    </button>
-                </div>
-                <div className="propertiesView-input inline">
-                    <p>Toggle Follow to Outer Context</p>
-                    <button
-                        style={{ background: !this.sourceAnchor?.followLinkToOuterContext ? '' : '#4476f7', borderRadius: 3 }}
-                        onPointerDown={e => this.toggleAnchorProp(e, 'followLinkToOuterContext', this.sourceAnchor)}
-                        onClick={e => e.stopPropagation()}
-                        className="propertiesButton">
-                        <FontAwesomeIcon className="fa-icon" icon={faWindowMaximize as IconLookup} size="lg" />
-                    </button>
-                </div>
-                <div className="propertiesView-input inline">
-                    <p>Toggle Target (Show/Hide)</p>
-                    <button
-                        style={{ background: !this.sourceAnchor?.followLinkToggle ? '' : '#4476f7', borderRadius: 3 }}
-                        onPointerDown={e => this.toggleAnchorProp(e, 'followLinkToggle', this.sourceAnchor)}
-                        onClick={e => e.stopPropagation()}
-                        className="propertiesButton">
-                        <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
-                    </button>
-                </div>
-                <div className="propertiesView-input inline">
-                    <p>Ease Transitions</p>
-                    <button
-                        style={{ background: this.sourceAnchor?.followLinkEase === 'linear' ? '' : '#4476f7', borderRadius: 3 }}
-                        onPointerDown={e => this.toggleAnchorProp(e, 'followLinkEase', this.sourceAnchor, 'ease', 'linear')}
-                        onClick={e => e.stopPropagation()}
-                        className="propertiesButton">
-                        <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
-                    </button>
-                </div>
-                <div className="propertiesView-input inline">
-                    <p>Capture Offset to Target</p>
-                    <button
-                        style={{ background: this.sourceAnchor?.followLinkXoffset === undefined ? '' : '#4476f7', borderRadius: 3 }}
-                        onPointerDown={e => {
-                            this.toggleAnchorProp(e, 'followLinkXoffset', this.sourceAnchor, NumCast(this.destinationAnchor?.x) - NumCast(this.sourceAnchor?.x), undefined);
-                            this.toggleAnchorProp(e, 'followLinkYoffset', this.sourceAnchor, NumCast(this.destinationAnchor?.y) - NumCast(this.sourceAnchor?.y), undefined);
-                        }}
-                        onClick={e => e.stopPropagation()}
-                        className="propertiesButton">
-                        <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
-                    </button>
-                </div>
-                <div className="propertiesView-input inline">
-                    <p>Center Target (no zoom)</p>
-                    <button
-                        style={{ background: this.sourceAnchor?.followLinkZoom ? '' : '#4476f7', borderRadius: 3 }}
-                        onPointerDown={e => this.toggleAnchorProp(e, 'followLinkZoom', this.sourceAnchor)}
-                        onClick={e => e.stopPropagation()}
-                        className="propertiesButton">
-                        <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
-                    </button>
-                </div>
-                <div className="propertiesView-input inline" style={{ display: 'grid', gridTemplateColumns: '78px calc(100% - 108px) 50px' }}>
-                    <p>Zoom %</p>
-                    <div className="ribbon-property" style={{ display: !targZoom ? 'none' : 'inline-flex' }}>
-                        <input className="presBox-input" style={{ width: '100%' }} readOnly={true} type="number" value={zoom} />
-                        <div className="ribbon-propertyUpDown" style={{ display: 'flex', flexDirection: 'column' }}>
-                            <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setZoom(String(zoom), 0.1))}>
-                                <FontAwesomeIcon icon={'caret-up'} />
+                {!hasSelectedAnchor ? null : (
+                    <div className="propertiesView-section">
+                        <div className="propertiesView-input inline first" style={{ display: 'grid', gridTemplateColumns: '84px calc(100% - 84px)' }}>
+                            <p>Follow by</p>
+                            <select onChange={e => this.changeFollowBehavior(e.currentTarget.value === 'Default' ? undefined : e.currentTarget.value)} value={Cast(this.sourceAnchor?.followLinkLocation, 'string', null)}>
+                                <option value={undefined}>Default</option>
+                                <option value={OpenWhere.addLeft}>Opening in new left pane</option>
+                                <option value={OpenWhere.addRight}>Opening in new right pane</option>
+                                <option value={OpenWhere.replaceLeft}>Replacing left tab</option>
+                                <option value={OpenWhere.replaceRight}>Replacing right tab</option>
+                                <option value={OpenWhere.lightbox}>Opening in lightbox</option>
+                                <option value={OpenWhere.add}>Opening in new tab</option>
+                                <option value={OpenWhere.replace}>Replacing current tab</option>
+                                <option value={OpenWhere.inParent}>Opening in same collection</option>
+                                {LinkManager.currentLink?.linksToAnnotation ? <option value="openExternal">Open in external page</option> : null}
+                            </select>
+                        </div>
+                        <div className="propertiesView-input inline first" style={{ display: 'grid', gridTemplateColumns: '84px calc(100% - 134px) 50px' }}>
+                            <p>Animation</p>
+                            <select style={{ width: '100%', gridColumn: 2 }} onChange={e => this.changeAnimationBehavior(e.currentTarget.value)} value={StrCast(this.sourceAnchor?.followLinkAnimEffect, 'default')}>
+                                <option value="default">Default</option>
+                                {[PresEffect.None, PresEffect.Zoom, PresEffect.Lightspeed, PresEffect.Fade, PresEffect.Flip, PresEffect.Rotate, PresEffect.Bounce, PresEffect.Roll].map(effect => (
+                                    <option key={effect.toString()} value={effect.toString()}>
+                                        {effect.toString()}
+                                    </option>
+                                ))}
+                            </select>
+                            <div className="effectDirection" style={{ marginLeft: '10px', display: 'grid', width: 40, height: 36, gridColumn: 3, gridTemplateRows: '12px 12px 12px' }}>
+                                {this.animationDirection(PresEffectDirection.Left, 'angle-right', 1, 2, {})}
+                                {this.animationDirection(PresEffectDirection.Right, 'angle-left', 3, 2, {})}
+                                {this.animationDirection(PresEffectDirection.Top, 'angle-down', 2, 1, {})}
+                                {this.animationDirection(PresEffectDirection.Bottom, 'angle-up', 2, 3, {})}
+                                {this.animationDirection(PresEffectDirection.Center, '', 2, 2, { width: 10, height: 10, alignSelf: 'center' })}
                             </div>
-                            <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setZoom(String(zoom), -0.1))}>
-                                <FontAwesomeIcon icon={'caret-down'} />
+                        </div>
+                        {PresBox.inputter(
+                            '0.1',
+                            '0.1',
+                            '10',
+                            NumCast(this.sourceAnchor?.followLinkTransitionTime) / 1000,
+                            true,
+                            (val: string) => PresBox.SetTransitionTime(val, (timeInMS: number) => this.sourceAnchor && (this.sourceAnchor.followLinkTransitionTime = timeInMS)),
+                            indent
+                        )}{' '}
+                        <div
+                            className={'slider-headers'}
+                            style={{
+                                display: 'grid',
+                                justifyContent: 'space-between',
+                                width: `calc(100% - ${indent * 2}px)`,
+                                marginLeft: indent,
+                                marginRight: indent,
+                                gridTemplateColumns: 'auto auto',
+                                borderTop: 'solid',
+                            }}>
+                            <div className="slider-text">Fast</div>
+                            <div className="slider-text">Slow</div>
+                        </div>{' '}
+                        <div className="propertiesView-input inline">
+                            <p>Play Target Audio</p>
+                            <button
+                                style={{ background: !this.sourceAnchor?.followLinkAudio ? '' : '#4476f7', borderRadius: 3 }}
+                                onPointerDown={e => this.toggleAnchorProp(e, 'followLinkAudio', this.sourceAnchor)}
+                                onClick={e => e.stopPropagation()}
+                                className="propertiesButton">
+                                <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
+                            </button>
+                        </div>
+                        <div className="propertiesView-input inline">
+                            <p>Zoom Text Selections</p>
+                            <button
+                                style={{ background: !this.sourceAnchor?.followLinkZoomText ? '' : '#4476f7', borderRadius: 3 }}
+                                onPointerDown={e => this.toggleAnchorProp(e, 'followLinkZoomText', this.sourceAnchor)}
+                                onClick={e => e.stopPropagation()}
+                                className="propertiesButton">
+                                <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
+                            </button>
+                        </div>
+                        <div className="propertiesView-input inline">
+                            <p>Toggle Follow to Outer Context</p>
+                            <button
+                                style={{ background: !this.sourceAnchor?.followLinkToOuterContext ? '' : '#4476f7', borderRadius: 3 }}
+                                onPointerDown={e => this.toggleAnchorProp(e, 'followLinkToOuterContext', this.sourceAnchor)}
+                                onClick={e => e.stopPropagation()}
+                                className="propertiesButton">
+                                <FontAwesomeIcon className="fa-icon" icon={faWindowMaximize as IconLookup} size="lg" />
+                            </button>
+                        </div>
+                        <div className="propertiesView-input inline">
+                            <p>Toggle Target (Show/Hide)</p>
+                            <button
+                                style={{ background: !this.sourceAnchor?.followLinkToggle ? '' : '#4476f7', borderRadius: 3 }}
+                                onPointerDown={e => this.toggleAnchorProp(e, 'followLinkToggle', this.sourceAnchor)}
+                                onClick={e => e.stopPropagation()}
+                                className="propertiesButton">
+                                <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
+                            </button>
+                        </div>
+                        <div className="propertiesView-input inline">
+                            <p>Ease Transitions</p>
+                            <button
+                                style={{ background: this.sourceAnchor?.followLinkEase === 'linear' ? '' : '#4476f7', borderRadius: 3 }}
+                                onPointerDown={e => this.toggleAnchorProp(e, 'followLinkEase', this.sourceAnchor, 'ease', 'linear')}
+                                onClick={e => e.stopPropagation()}
+                                className="propertiesButton">
+                                <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
+                            </button>
+                        </div>
+                        <div className="propertiesView-input inline">
+                            <p>Capture Offset to Target</p>
+                            <button
+                                style={{ background: this.sourceAnchor?.followLinkXoffset === undefined ? '' : '#4476f7', borderRadius: 3 }}
+                                onPointerDown={e => {
+                                    this.toggleAnchorProp(e, 'followLinkXoffset', this.sourceAnchor, NumCast(this.destinationAnchor?.x) - NumCast(this.sourceAnchor?.x), undefined);
+                                    this.toggleAnchorProp(e, 'followLinkYoffset', this.sourceAnchor, NumCast(this.destinationAnchor?.y) - NumCast(this.sourceAnchor?.y), undefined);
+                                }}
+                                onClick={e => e.stopPropagation()}
+                                className="propertiesButton">
+                                <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
+                            </button>
+                        </div>
+                        <div className="propertiesView-input inline">
+                            <p>Center Target (no zoom)</p>
+                            <button
+                                style={{ background: this.sourceAnchor?.followLinkZoom ? '' : '#4476f7', borderRadius: 3 }}
+                                onPointerDown={e => this.toggleAnchorProp(e, 'followLinkZoom', this.sourceAnchor)}
+                                onClick={e => e.stopPropagation()}
+                                className="propertiesButton">
+                                <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
+                            </button>
+                        </div>
+                        <div className="propertiesView-input inline" style={{ display: 'grid', gridTemplateColumns: '78px calc(100% - 108px) 50px' }}>
+                            <p>Zoom %</p>
+                            <div className="ribbon-property" style={{ display: !targZoom ? 'none' : 'inline-flex' }}>
+                                <input className="presBox-input" style={{ width: '100%' }} readOnly={true} type="number" value={zoom} />
+                                <div className="ribbon-propertyUpDown" style={{ display: 'flex', flexDirection: 'column' }}>
+                                    <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setZoom(String(zoom), 0.1))}>
+                                        <FontAwesomeIcon icon={'caret-up'} />
+                                    </div>
+                                    <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setZoom(String(zoom), -0.1))}>
+                                        <FontAwesomeIcon icon={'caret-down'} />
+                                    </div>
+                                </div>
                             </div>
+                            <button
+                                style={{ background: !targZoom || this.sourceAnchor?.followLinkZoomScale === 0 ? '' : '#4476f7', borderRadius: 3, gridColumn: 3 }}
+                                onPointerDown={e => this.toggleAnchorProp(e, 'followLinkZoom', this.sourceAnchor)}
+                                onClick={e => e.stopPropagation()}
+                                className="propertiesButton">
+                                <FontAwesomeIcon className="fa-icon" icon={faArrowRight as IconLookup} size="lg" />
+                            </button>
                         </div>
+                        {!targZoom ? null : PresBox.inputter('0', '1', '100', zoom, true, this.setZoom, 30)}
+                        <div
+                            className={'slider-headers'}
+                            style={{
+                                display: !targZoom ? 'none' : 'grid',
+                                justifyContent: 'space-between',
+                                width: `calc(100% - ${indent * 2}px)`,
+                                marginLeft: indent,
+                                marginRight: indent,
+                                gridTemplateColumns: 'auto auto',
+                                borderTop: 'solid',
+                            }}>
+                            <div className="slider-text">0%</div>
+                            <div className="slider-text">100%</div>
+                        </div>{' '}
                     </div>
-                    <button
-                        style={{ background: !targZoom || this.sourceAnchor?.followLinkZoomScale === 0 ? '' : '#4476f7', borderRadius: 3, gridColumn: 3 }}
-                        onPointerDown={e => this.toggleAnchorProp(e, 'followLinkZoom', this.sourceAnchor)}
-                        onClick={e => e.stopPropagation()}
-                        className="propertiesButton">
-                        <FontAwesomeIcon className="fa-icon" icon={faArrowRight as IconLookup} size="lg" />
-                    </button>
-                </div>
-                {!targZoom ? null : PresBox.inputter('0', '1', '100', zoom, true, this.setZoom, 30)}
-                <div
-                    className={'slider-headers'}
-                    style={{
-                        display: !targZoom ? 'none' : 'grid',
-                        justifyContent: 'space-between',
-                        width: `calc(100% - ${indent * 2}px)`,
-                        marginLeft: indent,
-                        marginRight: indent,
-                        gridTemplateColumns: 'auto auto',
-                        borderTop: 'solid',
-                    }}>
-                    <div className="slider-text">0%</div>
-                    <div className="slider-text">100%</div>
-                </div>{' '}
-            </div>
-        )}
-    </>
+                )}
+            </>
+        );
     }
 
     /**
@@ -1723,23 +1659,20 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                             width: this.props.width,
                             minWidth: this.props.width,
                         }}>
-                        <div className = "propertiesView-propAndInfoGrouping">
+                        <div className="propertiesView-propAndInfoGrouping">
                             <div className="propertiesView-title" style={{ width: this.props.width }}>
                                 Properties
                             </div>
-                            <div className = "propertiesView-info" onClick={() => window.open('https://brown-dash.github.io/Dash-Documentation/')}>
-                                 <GrCircleInformation/> </div>
-
+                            <div className="propertiesView-info" onClick={() => window.open('https://brown-dash.github.io/Dash-Documentation/')}>
+                                <GrCircleInformation />{' '}
+                            </div>
                         </div>
 
-                        
                         <div className="propertiesView-name">{this.editableTitle}</div>
-                        <div className = "propertiesView-type"> {this.currentType} </div>
+                        <div className="propertiesView-type"> {this.currentType} </div>
                         {this.contextsSubMenu}
                         {this.linksSubMenu}
-                        {!this.selectedDoc || !LinkManager.currentLink || (!hasSelectedAnchor && this.selectedDoc !== LinkManager.currentLink) ? null : (
-                            this.linkProperties
-                        )}
+                        {!this.selectedDoc || !LinkManager.currentLink || (!hasSelectedAnchor && this.selectedDoc !== LinkManager.currentLink) ? null : this.linkProperties}
                         {this.inkSubMenu}
                         {this.optionsSubMenu}
                         {this.fieldsSubMenu}
@@ -1760,7 +1693,6 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                             Presentation
                         </div>
                         <div className="propertiesView-name" style={{ borderBottom: 0 }}>
-                         
                             {this.editableTitle}
                             <div className="propertiesView-presSelected">
                                 <div className="propertiesView-selectedCount">{PresBox.Instance.selectedArray.size} selected</div>
@@ -1772,7 +1704,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                                 <div className="propertiesView-presTrails-title" onPointerDown={action(() => (this.openPresTransitions = !this.openPresTransitions))} style={{ backgroundColor: this.openPresTransitions ? 'black' : '' }}>
                                     &nbsp; <FontAwesomeIcon style={{ alignSelf: 'center' }} icon={'rocket'} /> &nbsp; Transitions
                                     <div className="propertiesView-presTrails-title-icon">
-                                        <FontAwesomeIcon icon={this.openPresTransitions ? 'caret-down' : 'caret-right'} size="lg"  />
+                                        <FontAwesomeIcon icon={this.openPresTransitions ? 'caret-down' : 'caret-right'} size="lg" />
                                     </div>
                                 </div>
                                 {this.openPresTransitions ? <div className="propertiesView-presTrails-content">{PresBox.Instance.transitionDropdown}</div> : null}
@@ -1786,7 +1718,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                                     style={{ backgroundColor: this.openPresTransitions ? 'black' : '' }}>
                                     &nbsp; <FontAwesomeIcon style={{ alignSelf: 'center' }} icon={'rocket'} /> &nbsp; Visibilty
                                     <div className="propertiesView-presTrails-title-icon">
-                                        <FontAwesomeIcon icon={this.openPresVisibilityAndDuration ? 'caret-down' : 'caret-right'} size="lg"  />
+                                        <FontAwesomeIcon icon={this.openPresVisibilityAndDuration ? 'caret-down' : 'caret-right'} size="lg" />
                                     </div>
                                 </div>
                                 {this.openPresVisibilityAndDuration ? <div className="propertiesView-presTrails-content">{PresBox.Instance.visibiltyDurationDropdown}</div> : null}
@@ -1797,7 +1729,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                                 <div className="propertiesView-presTrails-title" onPointerDown={action(() => (this.openPresProgressivize = !this.openPresProgressivize))} style={{ backgroundColor: this.openPresTransitions ? 'black' : '' }}>
                                     &nbsp; <FontAwesomeIcon style={{ alignSelf: 'center' }} icon={'rocket'} /> &nbsp; Progressivize
                                     <div className="propertiesView-presTrails-title-icon">
-                                        <FontAwesomeIcon icon={this.openPresProgressivize ? 'caret-down' : 'caret-right'} size="lg"  />
+                                        <FontAwesomeIcon icon={this.openPresProgressivize ? 'caret-down' : 'caret-right'} size="lg" />
                                     </div>
                                 </div>
                                 {this.openPresProgressivize ? <div className="propertiesView-presTrails-content">{PresBox.Instance.progressivizeDropdown}</div> : null}
@@ -1808,7 +1740,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                                 <div className="propertiesView-presTrails-title" onPointerDown={action(() => (this.openSlideOptions = !this.openSlideOptions))} style={{ backgroundColor: this.openSlideOptions ? 'black' : '' }}>
                                     &nbsp; <FontAwesomeIcon style={{ alignSelf: 'center' }} icon={type === DocumentType.AUDIO ? 'file-audio' : 'file-video'} /> &nbsp; {type === DocumentType.AUDIO ? 'Audio Options' : 'Video Options'}
                                     <div className="propertiesView-presTrails-title-icon">
-                                        <FontAwesomeIcon icon={this.openSlideOptions ? 'caret-down' : 'caret-right'} size="lg"  />
+                                        <FontAwesomeIcon icon={this.openSlideOptions ? 'caret-down' : 'caret-right'} size="lg" />
                                     </div>
                                 </div>
                                 {this.openSlideOptions ? <div className="propertiesView-presTrails-content">{PresBox.Instance.mediaOptionsDropdown}</div> : null}
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index bbbad3690..94748e884 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -22,7 +22,7 @@ import { 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 { BsArrowDown, BsArrowUp, BsArrowDownUp } from 'react-icons/bs';
 import './StyleProvider.scss';
 import React = require('react');
 
@@ -161,7 +161,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
                 ''
             );
         case StyleProp.Color:
-            if (MainView.Instance.LastButton === doc) return Doc.UserDoc().userBackgroundColor;
+            if (MainView.Instance.LastButton === doc) return SettingsManager.Instance.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));
@@ -208,12 +208,10 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
                 case DocumentType.PRES:        docColor = docColor || (darkScheme() ? 'transparent' : 'transparent'); break;
                 case DocumentType.FONTICON:    docColor = boxBackground ? undefined : docColor || Colors.DARK_GRAY; break;
                 case DocumentType.RTF:         docColor = docColor || (darkScheme() ? Colors.DARK_GRAY : Colors.LIGHT_GRAY); break;
-                case DocumentType.FILTER:      docColor = docColor || (darkScheme() ? Colors.DARK_GRAY : 'rgba(105, 105, 105, 0.432)'); break;
                 case DocumentType.INK:         docColor = doc?.stroke_isInkMask ? 'rgba(0,0,0,0.7)' : undefined; break;
                 case DocumentType.EQUATION:    docColor = docColor || 'transparent'; break;
                 case DocumentType.LABEL:       docColor = docColor || (darkScheme() ? Colors.DARK_GRAY : Colors.LIGHT_GRAY); break;
                 case DocumentType.BUTTON:      docColor = docColor || (darkScheme() ? Colors.DARK_GRAY : Colors.LIGHT_GRAY); break;
-                case DocumentType.LINKANCHOR:  docColor = isAnchor ? Colors.LIGHT_BLUE : 'transparent'; break;
                 case DocumentType.LINK:        docColor = (isAnchor ? docColor : '') || 'transparent'; break;
                 case DocumentType.IMG:
                 case DocumentType.WEB:
@@ -224,7 +222,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)
-                            ? StrCast(Doc.UserDoc().userBackgroundColor)
+                            ? SettingsManager.Instance.userBackgroundColor
                             : doc.annotationOn
                             ? '#00000010' // faint interior for collections on PDFs, images, etc
                             : doc?._isGroup
diff --git a/src/client/views/UndoStack.tsx b/src/client/views/UndoStack.tsx
index caf04cc1b..a551e5332 100644
--- a/src/client/views/UndoStack.tsx
+++ b/src/client/views/UndoStack.tsx
@@ -7,6 +7,7 @@ import { StrCast } from '../../fields/Types';
 import { Doc } from '../../fields/Doc';
 import { Popup, Type, isDark } from 'browndash-components';
 import { Colors } from './global/globalEnums';
+import { SettingsManager } from '../util/SettingsManager';
 
 interface UndoStackProps {
     width?: number;
@@ -18,35 +19,37 @@ export class UndoStack extends React.Component<UndoStackProps> {
     @observable static HideInline: boolean;
     @observable static Expand: boolean;
     render() {
-        const background = UndoManager.batchCounter.get() ? 'yellow' : StrCast(Doc.UserDoc().userBackgroundColor)
+        const background = UndoManager.batchCounter.get() ? 'yellow' : SettingsManager.Instance.userBackgroundColor;
         return this.props.inline && UndoStack.HideInline ? null : (
             <div className="undoStack-outerContainer">
-                <Popup 
+                <Popup
                     text={'Undo/Redo Stack'}
                     color={UndoManager.batchCounter.get() ? 'yellow' : StrCast(Doc.UserDoc().userVariantColor)}
                     placement={`top-start`}
                     type={Type.TERT}
                     popup={
-                    <div className="undoStack-commandsContainer" ref={r => r?.scroll({ behavior: 'auto', top: r?.scrollHeight + 20 })} 
-                        style={{ 
-                            background: background,
-                            color: isDark(background) ? Colors.LIGHT_GRAY : Colors.DARK_GRAY
-                        }}>
-                        {UndoManager.undoStackNames.map((name, i) => (
-                            <div className="undoStack-resultContainer" key={i}>
-                                <div className="undoStack-commandString">{name.replace(/[^\.]*\./, '')}</div>
-                            </div>
-                        ))}
-                        {Array.from(UndoManager.redoStackNames)
-                            .reverse()
-                            .map((name, i) => (
+                        <div
+                            className="undoStack-commandsContainer"
+                            ref={r => r?.scroll({ behavior: 'auto', top: r?.scrollHeight + 20 })}
+                            style={{
+                                background: background,
+                                color: isDark(background) ? Colors.LIGHT_GRAY : Colors.DARK_GRAY,
+                            }}>
+                            {UndoManager.undoStackNames.map((name, i) => (
                                 <div className="undoStack-resultContainer" key={i}>
-                                    <div className="undoStack-commandString" style={{ fontWeight: 'bold', color: 'red' }}>
-                                        {name.replace(/[^\.]*\./, '')}
-                                    </div>
+                                    <div className="undoStack-commandString">{name.replace(/[^\.]*\./, '')}</div>
                                 </div>
-                        ))}
-                    </div>    
+                            ))}
+                            {Array.from(UndoManager.redoStackNames)
+                                .reverse()
+                                .map((name, i) => (
+                                    <div className="undoStack-resultContainer" key={i}>
+                                        <div className="undoStack-commandString" style={{ fontWeight: 'bold', color: 'red' }}>
+                                            {name.replace(/[^\.]*\./, '')}
+                                        </div>
+                                    </div>
+                                ))}
+                        </div>
                     }
                 />
             </div>
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 16982595d..0052c4196 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -164,7 +164,7 @@ export class CollectionDockingView extends CollectionSubView() {
     public static AddSplit(document: Doc, pullSide: OpenWhereMod, stack?: any, panelName?: string, keyValue?: boolean) {
         if (document?._type_collection === CollectionViewType.Docking && !keyValue) return DashboardView.openDashboard(document);
         if (!CollectionDockingView.Instance) return false;
-        const tab = Array.from(CollectionDockingView.Instance.tabMap).find(tab => tab.DashDoc === document && !keyValue);
+        const tab = Array.from(CollectionDockingView.Instance.tabMap).find(tab => tab.DashDoc === document && !tab.contentItem.config.props.keyValue && !keyValue);
         if (tab) {
             tab.header.parent.setActiveContentItem(tab.contentItem);
             return true;
@@ -466,7 +466,10 @@ export class CollectionDockingView extends CollectionSubView() {
         this._flush = this._flush ?? UndoManager.StartBatch('tab movement');
         if (tab.DashDoc && ![DocumentType.PRES].includes(tab.DashDoc?.type) && !tab.contentItem.config.props.keyValue) {
             Doc.AddDocToList(Doc.MyHeaderBar, 'data', tab.DashDoc);
-            Doc.AddDocToList(Doc.MyRecentlyClosed, 'data', tab.DashDoc, undefined, true, true);
+            // if you close a tab that is not embedded somewhere else (an embedded Doc can be opened simultaneously in a tab), then add the tab to recently closed
+            if (tab.DashDoc.embedContainer === this.rootDoc) tab.DashDoc.embedContainer = undefined;
+            if (!tab.DashDoc.embedContainer) Doc.AddDocToList(Doc.MyRecentlyClosed, 'data', tab.DashDoc, undefined, true, true);
+            Doc.RemoveDocFromList(Doc.GetProto(tab.DashDoc), 'proto_embeddings', tab.DashDoc);
         }
         if (CollectionDockingView.Instance) {
             const dview = CollectionDockingView.Instance.props.Document;
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 5135cfb57..f65e8698f 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: StrCast(Doc.UserDoc().userBackgroundColor),
+                    background: SettingsManager.Instance.userBackgroundColor,
                     // borderColor: StrCast(Doc.UserDoc().userColor)
                 }}>
                 {this.contMenuButtons}
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index a5c276125..056204ad3 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -669,7 +669,6 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
         if (menuDoc) {
             const width: number = NumCast(menuDoc._width, 30);
             const height: number = NumCast(menuDoc._height, 30);
-            console.log(menuDoc.title, width, height);
             return (
                 <div className="buttonMenu-docBtn" style={{ width: width, height: height }}>
                     <DocumentView
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 00137736d..ea3b5065f 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -150,6 +150,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
                 console.log('WHAAAT');
             }
             dragData.dropAction = dropAction && !isAlreadyInTree() ? dropAction : sameTree ? 'same' : dragData.dropAction;
+            e.stopPropagation();
         }
     };
 
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 67b7b39dd..d787f5262 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -396,7 +396,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
         return NumCast(Cast(PresBox.Instance.activeItem.presentationTargetDoc, Doc, null)._currentFrame);
     };
     static Activate = (tabDoc: Doc) => {
-        const tab = Array.from(CollectionDockingView.Instance?.tabMap!).find(tab => tab.DashDoc === tabDoc);
+        const tab = Array.from(CollectionDockingView.Instance?.tabMap!).find(tab => tab.DashDoc === tabDoc && !tab.contentItem.config.props.keyValue);
         tab?.header.parent.setActiveContentItem(tab.contentItem); // glr: Panning does not work when this is set - (this line is for trying to make a tab that is not topmost become topmost)
         return tab !== undefined;
     };
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index fb23fc7f1..6e0ccd4be 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -127,7 +127,7 @@ export class TreeView extends React.Component<TreeViewProps> {
             : this.props.treeView.fileSysMode
             ? this.doc.isFolder
                 ? this.fieldKey
-                : 'embeddings' // for displaying
+                : 'data' // file system folders display their contents (data).  used to be they displayed their embeddings but now its a tree structure and not a flat list
             : this.props.treeView.outlineMode || this.childDocs
             ? this.fieldKey
             : Doc.noviceMode
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 090cf356c..7c53bfdbe 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -377,7 +377,6 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
             : ((doc: Doc) => {
                   Doc.GetProto(doc).data = new List<Doc>(selected);
                   Doc.GetProto(doc).title = makeGroup ? 'grouping' : 'nested freeform';
-                  !this.props.isAnnotationOverlay && Doc.AddFileOrphan(Doc.GetProto(doc));
                   doc._freeform_panX = doc._freeform_panY = 0;
                   return doc;
               })(Doc.MakeCopy(Doc.UserDoc().emptyCollection as Doc, true));
diff --git a/src/client/views/global/globalScripts.ts b/src/client/views/global/globalScripts.ts
index 79842047b..256377758 100644
--- a/src/client/views/global/globalScripts.ts
+++ b/src/client/views/global/globalScripts.ts
@@ -197,7 +197,6 @@ ScriptingGlobals.add(function toggleCharStyle(charStyle: attrname, checkResult?:
 });
 
 export function checkInksToGroup() {
-    // console.log("getting here to inks group");
     if (Doc.ActiveTool === InkTool.Write) {
         CollectionFreeFormView.collectionsWithUnprocessedInk.forEach(ffView => {
             // TODO: nda - will probably want to go through ffView unprocessed docs and then see if any of the inksToGroup docs are in it and only use those
diff --git a/src/client/views/newlightbox/ExploreView/ExploreView.tsx b/src/client/views/newlightbox/ExploreView/ExploreView.tsx
index 44a0bcd5f..a1d6375c4 100644
--- a/src/client/views/newlightbox/ExploreView/ExploreView.tsx
+++ b/src/client/views/newlightbox/ExploreView/ExploreView.tsx
@@ -12,14 +12,11 @@ export const ExploreView = (props: IExploreView) => {
         <div className={`exploreView-container`}>
             {recs &&
                 recs.map(rec => {
-                    console.log(rec.embedding, bounds);
                     const x_bound: number = Math.max(Math.abs(bounds.max_x), Math.abs(bounds.min_x));
                     const y_bound: number = Math.max(Math.abs(bounds.max_y), Math.abs(bounds.min_y));
-                    console.log(x_bound, y_bound);
                     if (rec.embedding) {
                         const x = (rec.embedding.x / x_bound) * 50;
                         const y = (rec.embedding.y / y_bound) * 50;
-                        console.log(x, y);
                         return (
                             <div className={`exploreView-doc`} onClick={() => {}} style={{ top: `calc(50% + ${y}%)`, left: `calc(50% + ${x}%)` }}>
                                 {rec.title}
diff --git a/src/client/views/newlightbox/components/Recommendation/Recommendation.tsx b/src/client/views/newlightbox/components/Recommendation/Recommendation.tsx
index b9d05c531..2c2f04b9f 100644
--- a/src/client/views/newlightbox/components/Recommendation/Recommendation.tsx
+++ b/src/client/views/newlightbox/components/Recommendation/Recommendation.tsx
@@ -22,7 +22,6 @@ export const Recommendation = (props: IRecommendation) => {
                         doc = docView.rootDoc;
                     }
                 } else if (data) {
-                    console.log(data, type);
                     switch (type) {
                         case 'YouTube':
                             console.log('create ', type, 'document');
diff --git a/src/client/views/nodes/DataVizBox/utils/D3Utils.ts b/src/client/views/nodes/DataVizBox/utils/D3Utils.ts
index e1ff6f8eb..10bfb0c64 100644
--- a/src/client/views/nodes/DataVizBox/utils/D3Utils.ts
+++ b/src/client/views/nodes/DataVizBox/utils/D3Utils.ts
@@ -34,7 +34,6 @@ export const createLineGenerator = (xScale: d3.ScaleLinear<number, number, never
 };
 
 export const xAxisCreator = (g: d3.Selection<SVGGElement, unknown, null, undefined>, height: number, xScale: d3.ScaleLinear<number, number, never>) => {
-    console.log('x axis creator being called');
     g.attr('class', 'x-axis').attr('transform', `translate(0,${height})`).call(d3.axisBottom(xScale).tickSize(15));
 };
 
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 70d2f95ea..d379b2b52 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1,5 +1,5 @@
 import { IconProp } from '@fortawesome/fontawesome-svg-core';
-import { action, computed, IReactionDisposer, observable, reaction, runInAction, trace } from 'mobx';
+import { action, computed, IReactionDisposer, observable, reaction, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
 import { computedFn } from 'mobx-utils';
 import { Bounce, Fade, Flip, LightSpeed, Roll, Rotate, Zoom } from 'react-reveal';
@@ -47,7 +47,6 @@ import { DocumentLinksButton } from './DocumentLinksButton';
 import './DocumentView.scss';
 import { FieldViewProps } from './FieldView';
 import { FormattedTextBox } from './formattedText/FormattedTextBox';
-import { KeyValueBox } from './KeyValueBox';
 import { LinkAnchorBox } from './LinkAnchorBox';
 import { PresEffect, PresEffectDirection } from './trails';
 import { PinProps, PresBox } from './trails/PresBox';
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx
index 86191de63..d69009415 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 { Height, Width } from '../../../fields/DocSymbols';
+import { DirectLinks, 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';
diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx
index de0b57fd7..4919ee94c 100644
--- a/src/client/views/nodes/MapBox/MapBox.tsx
+++ b/src/client/views/nodes/MapBox/MapBox.tsx
@@ -61,7 +61,6 @@ const script = document.createElement('script');
 script.defer = true;
 script.async = true;
 script.src = `https://maps.googleapis.com/maps/api/js?key=${apiKey}&libraries=places,drawing`;
-console.log(script.src);
 document.head.appendChild(script);
 
 /**
diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx
index 312b3c619..bbf56bdf9 100644
--- a/src/client/views/nodes/ScreenshotBox.tsx
+++ b/src/client/views/nodes/ScreenshotBox.tsx
@@ -224,7 +224,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
             const aud_chunks: any = [];
             this._audioRec.ondataavailable = (e: any) => aud_chunks.push(e.data);
             this._audioRec.onstop = async (e: any) => {
-                const [{ result }] = await Networking.UploadFilesToServer(aud_chunks.map((file: any) => ({file})));
+                const [{ result }] = await Networking.UploadFilesToServer(aud_chunks.map((file: any) => ({ file })));
                 if (!(result instanceof Error)) {
                     this.dataDoc[this.props.fieldKey + '-audio'] = new AudioField(result.accessPaths.agnostic.client);
                 }
@@ -235,9 +235,8 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
             this._videoRec.onstart = () => (this.dataDoc[this.props.fieldKey + '-recordingStart'] = new DateField(new Date()));
             this._videoRec.ondataavailable = (e: any) => vid_chunks.push(e.data);
             this._videoRec.onstop = async (e: any) => {
-                console.log('screenshotbox: upload');
                 const file = new File(vid_chunks, `${this.rootDoc[Id]}.mkv`, { type: vid_chunks[0].type, lastModified: Date.now() });
-                const [{ result }] = await Networking.UploadFilesToServer({file});
+                const [{ result }] = await Networking.UploadFilesToServer({ file });
                 this.dataDoc[this.fieldKey + '_duration'] = (new Date().getTime() - this.recordingStart!) / 1000;
                 if (!(result instanceof Error)) {
                     // convert this screenshotBox into normal videoBox
diff --git a/src/client/views/nodes/ScriptingBox.tsx b/src/client/views/nodes/ScriptingBox.tsx
index 3ad3c911d..7c8a1849e 100644
--- a/src/client/views/nodes/ScriptingBox.tsx
+++ b/src/client/views/nodes/ScriptingBox.tsx
@@ -610,7 +610,6 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
                         ' ': {
                             dataProvider: (token: any) => this.handleToken(token),
                             component: (blob: any) => {
-                                console.log('Blob', blob);
                                 return this.renderFuncListElement(blob.entity);
                             },
                             output: (item: any, trigger: any) => {
@@ -621,7 +620,6 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
                         '.': {
                             dataProvider: (token: any) => this.handleToken(token),
                             component: (blob: any) => {
-                                console.log('Blob', blob);
                                 return this.renderFuncListElement(blob.entity);
                             },
                             output: (item: any, trigger: any) => {
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 895bb80f0..1dcc445e8 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -96,6 +96,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
     private _scrollRef: React.RefObject<HTMLDivElement> = React.createRef();
     private _editorView: Opt<EditorView>;
     public _applyingChange: string = '';
+    private _finishingLink = false;
     private _searchIndex = 0;
     private _lastTimedMark: Mark | undefined = undefined;
     private _cachedLinks: Doc[] = [];
@@ -245,7 +246,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
         if (!pinProps && this._editorView?.state.selection.empty) return this.rootDoc;
         const anchor = Docs.Create.ConfigDocument({ title: StrCast(this.rootDoc.title), annotationOn: this.rootDoc });
         this.addDocument(anchor);
+        this._finishingLink = true;
         this.makeLinkAnchor(anchor, OpenWhere.addRight, undefined, 'Anchored Selection', false, addAsAnnotation);
+        this._finishingLink = false;
         PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), scrollable: true } }, this.rootDoc);
         return anchor;
     };
@@ -326,7 +329,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                     textChange && (dataDoc[this.fieldKey + '_modificationDate'] = new DateField(new Date(Date.now())));
                     if ((!prevData && !protoData) || newText || (!newText && !templateData)) {
                         // if no template, or there's text that didn't come from the layout template, write it to the document. (if this is driven by a template, then this overwrites the template text which is intended)
-                        if (this.props.isContentActive() && removeSelection(newJson) !== removeSelection(prevData?.Data)) {
+                        if ((this._finishingLink || this.props.isContentActive()) && removeSelection(newJson) !== removeSelection(prevData?.Data)) {
                             const numstring = NumCast(dataDoc[this.fieldKey], null);
                             dataDoc[this.fieldKey] = numstring !== undefined ? Number(newText) : new RichTextField(newJson, newText);
                             dataDoc[this.fieldKey + '_noTemplate'] = true; // mark the data field as being split from the template if it has been edited
@@ -457,8 +460,12 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                         if (node.firstChild === null && !node.marks.find((m: Mark) => m.type.name === schema.marks.noAutoLinkAnchor.name) && node.marks.find((m: Mark) => m.type.name === schema.marks.splitter.name)) {
                             alink =
                                 alink ??
-                                (LinkManager.Links(this.Document).find(link => Doc.AreProtosEqual(Cast(link.link_anchor_1, Doc, null), this.rootDoc) && Doc.AreProtosEqual(Cast(link.link_anchor_2, Doc, null), target)) ||
-                                    DocUtils.MakeLink(this.props.Document, target, { link_relationship: LinkManager.AutoKeywords })!);
+                                (LinkManager.Links(this.rootDoc).find(
+                                    link =>
+                                        Doc.AreProtosEqual(Cast(link.link_anchor_1, Doc, null), this.rootDoc) && //
+                                        Doc.AreProtosEqual(Cast(link.link_anchor_2, Doc, null), target)
+                                ) ||
+                                    DocUtils.MakeLink(this.rootDoc, target, { link_relationship: LinkManager.AutoKeywords })!);
                             newAutoLinks.add(alink);
                             const allAnchors = [{ href: Doc.localServerPath(target), title: 'a link', anchorId: this.props.Document[Id] }];
                             allAnchors.push(...(node.marks.find((m: Mark) => m.type.name === schema.marks.autoLinkAnchor.name)?.attrs.allAnchors ?? []));
@@ -840,7 +847,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
 
         const appearance = cm.findByDescription('Appearance...');
         const appearanceItems = appearance && 'subitems' in appearance ? appearance.subitems : [];
-        appearanceItems.push({ description: 'Change Perspective...', noexpand: true, subitems: changeItems, icon: 'external-link-alt' });
+        appearanceItems.push({ description: 'Change Style...', noexpand: true, subitems: changeItems, icon: 'external-link-alt' });
         // this.rootDoc.isTemplateDoc && appearanceItems.push({ description: "Make Default Layout", event: async () => Doc.UserDoc().defaultTextLayout = new PrefetchProxy(this.rootDoc), icon: "eye" });
 
         !Doc.noviceMode &&
@@ -1996,12 +2003,12 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
     }
     cycleAlternateText = () => {
         if (this.layoutDoc._layout_enableAltContentUI) {
-            const usePath = this.rootDoc[`${this.props.fieldKey}_usePath`];
+            const usePath = this.rootDoc[`_${this.props.fieldKey}_usePath`];
             this.rootDoc[`_${this.props.fieldKey}_usePath`] = usePath === undefined ? 'alternate' : usePath === 'alternate' ? 'alternate:hover' : undefined;
         }
     };
     @computed get overlayAlternateIcon() {
-        const usePath = this.rootDoc[`${this.props.fieldKey}_usePath`];
+        const usePath = this.rootDoc[`_${this.props.fieldKey}_usePath`];
         return (
             <Tooltip
                 title={
@@ -2080,7 +2087,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                         ? {}
                         : {
                               transform: `scale(${scale})`,
-                              transformOrigin: 'top left',
                               width: `${100 / scale}%`,
                               height: `${100 / scale}%`,
                           }),
diff --git a/src/client/views/nodes/formattedText/RichTextRules.ts b/src/client/views/nodes/formattedText/RichTextRules.ts
index ac1e7ce5d..8bafc2cef 100644
--- a/src/client/views/nodes/formattedText/RichTextRules.ts
+++ b/src/client/views/nodes/formattedText/RichTextRules.ts
@@ -243,13 +243,13 @@ export class RichTextRules {
 
             // create a text display of a metadata field on this or another document, or create a hyperlink portal to another document
             // [[<fieldKey> : <Doc>]]
-            // [[:Doc]] => hyperlink
+            // [[:docTitle]] => hyperlink
             // [[fieldKey]] => show field
             // [[fieldKey=value]] => show field and also set its value
-            // [[fieldKey:Doc]] => show field of doc
+            // [[fieldKey:docTitle]] => show field of doc
             new InputRule(new RegExp(/\[\[([a-zA-Z_\? \-0-9]*)(=[a-zA-Z_@\? /\-0-9]*)?(:[a-zA-Z_@:\.\? \-0-9]+)?\]\]$/), (state, match, start, end) => {
                 const fieldKey = match[1];
-                const docId = match[3]?.replace(':', '');
+                const docTitle = match[3]?.replace(':', '');
                 const value = match[2]?.substring(1);
                 const linkToDoc = (target: Doc) => {
                     const rstate = this.TextBox.EditorView?.state;
@@ -266,12 +266,12 @@ export class RichTextRules {
                     }
                 };
                 if (!fieldKey) {
-                    if (docId) {
-                        const target = DocServer.QUERY_SERVER_CACHE(docId);
-                        if (target) setTimeout(() => linkToDoc(target));
-                        else DocServer.GetRefField(docId).then(docx => linkToDoc((docx instanceof Doc && docx) || Docs.Create.FreeformDocument([], { title: docId + '(auto)', _width: 500, _height: 500 }, docId)));
-
-                        return state.tr.deleteRange(end - 1, end).deleteRange(start, start + 3);
+                    if (docTitle) {
+                        const target = DocServer.FindDocByTitle(docTitle);
+                        if (target) {
+                            setTimeout(() => linkToDoc(target));
+                            return state.tr.deleteRange(end - 1, end).deleteRange(start, start + 3);
+                        }
                     }
                     return state.tr;
                 }
@@ -279,8 +279,12 @@ export class RichTextRules {
                     const num = value.match(/^[0-9.]$/);
                     this.Document[DocData][fieldKey] = value === 'true' ? true : value === 'false' ? false : num ? Number(value) : value;
                 }
-                const fieldView = state.schema.nodes.dashField.create({ fieldKey, docId, hideKey: false });
-                return state.tr.setSelection(new TextSelection(state.doc.resolve(start), state.doc.resolve(end))).replaceSelectionWith(fieldView, true);
+                const target = DocServer.FindDocByTitle(docTitle);
+                if (target) {
+                    const fieldView = state.schema.nodes.dashField.create({ fieldKey, docId: target[Id], hideKey: false });
+                    return state.tr.setSelection(new TextSelection(state.doc.resolve(start), state.doc.resolve(end))).replaceSelectionWith(fieldView, true);
+                }
+                return state.tr;
             }),
 
             // create a text display of a metadata field on this or another document, or create a hyperlink portal to another document
diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx
index b877cc36a..e35e011e2 100644
--- a/src/client/views/pdf/AnchorMenu.tsx
+++ b/src/client/views/pdf/AnchorMenu.tsx
@@ -17,6 +17,7 @@ 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';
 
 @observer
 export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
@@ -262,7 +263,7 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
                     colorPicker={this.highlightColor}
                     color={StrCast(Doc.UserDoc().userColor)}
                 />
-                <ColorPicker colorPickerType={'github'} selectedColor={this.highlightColor} setSelectedColor={color => this.changeHighlightColor(color)} size={Size.XSMALL} />
+                <ColorPicker selectedColor={this.highlightColor} setSelectedColor={this.changeHighlightColor} size={Size.XSMALL} />
             </Group>
         );
     }
@@ -287,7 +288,7 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
     canSummarize = (): boolean => {
         const docs = SelectionManager.Docs();
         if (docs.length > 0) {
-            return docs.some(doc => doc.type === 'pdf' || doc.type === 'web');
+            return docs.some(doc => doc.type === DocumentType.PDF || doc.type === DocumentType.WEB);
         }
         return false;
     };
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index e911bd283..a28561107 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -18,6 +18,7 @@ import './SearchBox.scss';
 import { fetchRecommendations } from '../newlightbox/utils';
 import { IRecommendation, Recommendation } from '../newlightbox/components';
 import { Colors } from '../global/globalEnums';
+import { SettingsManager } from '../../util/SettingsManager';
 
 const DAMPENING_FACTOR = 0.9;
 const MAX_ITERATIONS = 25;
@@ -218,7 +219,7 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
     }
     @action
     static staticSearchCollection(rootDoc: Opt<Doc>, query: string) {
-        const blockedTypes = [DocumentType.PRESELEMENT, DocumentType.CONFIG, DocumentType.KVP, DocumentType.FILTER, DocumentType.SEARCH, DocumentType.SEARCHITEM, DocumentType.FONTICON, DocumentType.BUTTON, DocumentType.SCRIPTING];
+        const blockedTypes = [DocumentType.PRESELEMENT, DocumentType.CONFIG, DocumentType.KVP, DocumentType.SEARCH, DocumentType.FONTICON, DocumentType.BUTTON, DocumentType.SCRIPTING];
         const blockedKeys = [
             'x',
             'y',
@@ -398,22 +399,21 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
 
         if (query) {
             this.searchCollection(query);
-            const response = await fetchRecommendations('', query, [], true)
-            const recs = response.recommendations
-            const recommendations:IRecommendation[] = []
+            const response = await fetchRecommendations('', query, [], true);
+            const recs = response.recommendations;
+            const recommendations: IRecommendation[] = [];
             for (const key in recs) {
                 const title = recs[key].title;
-                console.log(title);
-                const url = recs[key].url
-                const type = recs[key].type
-                const text = recs[key].text
-                const transcript = recs[key].transcript
-                const previewUrl = recs[key].previewUrl
-                const embedding = recs[key].embedding
-                const distance = recs[key].distance
-                const source = recs[key].source
-                const related_concepts = recs[key].related_concepts
-                const docId = recs[key].doc_id
+                const url = recs[key].url;
+                const type = recs[key].type;
+                const text = recs[key].text;
+                const transcript = recs[key].transcript;
+                const previewUrl = recs[key].previewUrl;
+                const embedding = recs[key].embedding;
+                const distance = recs[key].distance;
+                const source = recs[key].source;
+                const related_concepts = recs[key].related_concepts;
+                const docId = recs[key].doc_id;
                 recommendations.push({
                     title: title,
                     data: url,
@@ -425,11 +425,11 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
                     distance: Math.round(distance * 100) / 100,
                     source: source,
                     related_concepts: related_concepts,
-                    docId: docId
-                })
+                    docId: docId,
+                });
             }
-            const setRecommendations = action(() => this._recommendations = recommendations)
-            setRecommendations()
+            const setRecommendations = action(() => (this._recommendations = recommendations));
+            setRecommendations();
         }
     };
 
@@ -461,7 +461,7 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
      */
     @computed
     public get selectOptions() {
-        const selectValues = ['all', 'rtf', 'image', 'pdf', 'web', 'video', 'audio', 'collection'];
+        const selectValues = ['all', DocumentType.RTF, DocumentType.IMG, DocumentType.PDF, DocumentType.WEB, DocumentType.VID, DocumentType.AUDIO, DocumentType.COL];
 
         return selectValues.map(value => (
             <option key={value} value={value}>
@@ -517,19 +517,19 @@ 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">{result[1].join(', ')}</div>
+                            <div className="searchBox-result-keys" style={{ color: SettingsManager.Instance.userVariantColor }}>
+                                {result[1].join(', ')}
+                            </div>
                         </div>
                     </Tooltip>
                 );
             }
         });
 
-        const recommendationsJSX: JSX.Element[] = this._recommendations.map((props) => (
-            <Recommendation {...props}/>
-        ))
+        const recommendationsJSX: JSX.Element[] = this._recommendations.map(props => <Recommendation {...props} />);
 
         return (
-            <div className="searchBox-container" style={{pointerEvents: 'all', background: StrCast(Doc.UserDoc().userBackgroundColor)}}>
+            <div className="searchBox-container" style={{ pointerEvents: 'all', color: SettingsManager.Instance.userColor, background: SettingsManager.Instance.userBackgroundColor }}>
                 <div className="searchBox-bar">
                     {isLinkSearch ? null : (
                         <select name="type" id="searchBox-type" className="searchBox-type" onChange={this.onSelectChange}>
@@ -552,20 +552,24 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
                         ref={this._inputRef}
                     />
                 </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-title">Results</div>
-                        <div className="section-subtitle">{`${validResults}` + ' result' + (validResults === 1 ? '' : 's')}</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-title">Results</div>
+                            <div className="section-subtitle">{`${validResults}` + ' result' + (validResults === 1 ? '' : 's')}</div>
+                        </div>
+                        <div className="searchBox-results-view">{resultsJSX}</div>
                     </div>
-                    <div className="searchBox-results-view">{resultsJSX}</div>
-                </div>}
-                {recommendationsJSX.length > 0 && <div className="searchBox-recommendations-container">
-                    <div className="section-header" style={{background: StrCast(Doc.UserDoc().userVariantColor, Colors.MEDIUM_BLUE)}}>
-                        <div className="section-title">Recommendations</div>
-                        <div className="section-subtitle">{`${validResults}` + ' result' + (validResults === 1 ? '' : 's')}</div>
+                )}
+                {recommendationsJSX.length > 0 && (
+                    <div className="searchBox-recommendations-container">
+                        <div className="section-header" style={{ background: StrCast(Doc.UserDoc().userVariantColor, Colors.MEDIUM_BLUE) }}>
+                            <div className="section-title">Recommendations</div>
+                            <div className="section-subtitle">{`${validResults}` + ' result' + (validResults === 1 ? '' : 's')}</div>
+                        </div>
+                        <div className="searchBox-recommendations-view">{recommendationsJSX}</div>
                     </div>
-                    <div className="searchBox-recommendations-view">{recommendationsJSX}</div>
-                </div>}
+                )}
             </div>
         );
     }
diff --git a/src/client/views/topbar/TopBar.tsx b/src/client/views/topbar/TopBar.tsx
index cb8eda9de..8caba930d 100644
--- a/src/client/views/topbar/TopBar.tsx
+++ b/src/client/views/topbar/TopBar.tsx
@@ -35,10 +35,14 @@ export class TopBar extends React.Component {
         });
     };
 
-    @computed get color() { return StrCast(Doc.UserDoc().userColor, Colors.LIGHT_GRAY); }
-    @computed get variantColor() { return StrCast(Doc.UserDoc().userVariantColor, Colors.MEDIUM_BLUE); }
+    @computed get color() {
+        return StrCast(Doc.UserDoc().userColor, Colors.LIGHT_GRAY);
+    }
+    @computed get variantColor() {
+        return StrCast(Doc.UserDoc().userVariantColor, Colors.MEDIUM_BLUE);
+    }
     @computed get backgroundColor() {
-        return PingManager.Instance.IsBeating ? StrCast(Doc.UserDoc().userBackgroundColor, Colors.DARK_GRAY) : Colors.MEDIUM_GRAY;
+        return PingManager.Instance.IsBeating ? SettingsManager.Instance.userBackgroundColor : Colors.MEDIUM_GRAY;
     }
 
     @observable happyHeart: boolean = PingManager.Instance.IsBeating;
@@ -102,7 +106,7 @@ export class TopBar extends React.Component {
                     tooltip="Open Dashboards"
                     size={Size.SMALL}
                     color={this.color}
-                    style={{fontWeight: 700, fontSize: '1rem'}}
+                    style={{ fontWeight: 700, fontSize: '1rem' }}
                     onClick={(e: React.MouseEvent) => {
                         const dashView = Doc.ActiveDashboard && DocumentManager.Instance.getDocumentView(Doc.ActiveDashboard);
                         ContextMenu.Instance.addItem({ description: 'Open Dashboard View', event: this.navigateToHome, icon: 'edit' });
@@ -134,7 +138,7 @@ export class TopBar extends React.Component {
     @computed get topbarRight() {
         return (
             <div className="topbar-right">
-                {Doc.ActiveDashboard ? 
+                {Doc.ActiveDashboard ? (
                     <Button
                         text={GetEffectiveAcl(Doc.ActiveDashboard) === AclAdmin ? 'Share' : 'View Original'}
                         type={Type.TERT}
@@ -143,15 +147,15 @@ export class TopBar extends React.Component {
                             SharingManager.Instance.open(undefined, Doc.ActiveDashboard);
                         }}
                     />
-                : null }
-                <IconButton tooltip={"Issue Reporter ⌘I"} size={Size.SMALL} color={this.color} onClick={ReportManager.Instance.open} icon={<FaBug />} />
-                <IconButton tooltip={"Documentation ⌘D"} size={Size.SMALL} color={this.color} onClick={() => window.open('https://brown-dash.github.io/Dash-Documentation/', '_blank')} icon={<FontAwesomeIcon icon="question-circle" />} />
-                <IconButton tooltip={"Settings ⌘⇧S"} size={Size.SMALL} color={this.color} onClick={SettingsManager.Instance.open} icon={<FontAwesomeIcon icon="cog" />} />
+                ) : null}
+                <IconButton tooltip={'Issue Reporter ⌘I'} size={Size.SMALL} color={this.color} onClick={ReportManager.Instance.open} icon={<FaBug />} />
+                <IconButton tooltip={'Documentation ⌘D'} size={Size.SMALL} color={this.color} onClick={() => window.open('https://brown-dash.github.io/Dash-Documentation/', '_blank')} icon={<FontAwesomeIcon icon="question-circle" />} />
+                <IconButton tooltip={'Settings ⌘⇧S'} size={Size.SMALL} color={this.color} onClick={SettingsManager.Instance.open} icon={<FontAwesomeIcon icon="cog" />} />
                 <IconButton
                     size={Size.SMALL}
                     onClick={ServerStats.Instance.open}
                     type={Type.TERT}
-                    tooltip={'Server is ' + (PingManager.Instance.IsBeating ? '' : 'NOT ') + 'running'}
+                    tooltip={'Server is ' + (PingManager.Instance.IsBeating ? '' : 'NOT ') + 'running ' + SettingsManager.Version}
                     color={this.happyHeart ? Colors.LIGHT_BLUE : Colors.ERROR_RED}
                     icon={<FontAwesomeIcon icon={this.happyHeart ? 'heart' : 'heart-broken'} />}
                 />
@@ -163,12 +167,14 @@ export class TopBar extends React.Component {
     render() {
         return (
             //TODO:glr Add support for light / dark mode
-            <div style={{ 
-                pointerEvents: 'all',
-                color: this.color,
-                background: this.backgroundColor,
-                // borderColor: this.color
-            }} className="topbar-container">
+            <div
+                style={{
+                    pointerEvents: 'all',
+                    color: this.color,
+                    background: this.backgroundColor,
+                    // borderColor: this.color
+                }}
+                className="topbar-container">
                 <div className="topbar-inner-container">
                     {this.topbarLeft}
                     {this.topbarCenter}
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 5a411a201..eb52cff88 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -238,22 +238,6 @@ export class Doc extends RefField {
     public static get MyFilesystem() {
         return DocCast(Doc.UserDoc().myFilesystem);
     }
-    public static get MyFileOrphans() {
-        return DocCast(Doc.UserDoc().myFileOrphans);
-    }
-    public static AddFileOrphan(doc: Doc) {
-        if (
-            doc &&
-            Doc.MyFileOrphans instanceof Doc &&
-            Doc.IsDataProto(doc) &&
-            !Doc.IsSystem(doc) &&
-            ![DocumentType.CONFIG, DocumentType.KVP, DocumentType.LINK, DocumentType.LINKANCHOR].includes(doc.type as any) &&
-            !doc.isFolder &&
-            !doc.annotationOn
-        ) {
-            Doc.AddDocToList(Doc.MyFileOrphans, undefined, doc);
-        }
-    }
     public static get MyTools() {
         return DocCast(Doc.UserDoc().myTools);
     }
@@ -388,7 +372,7 @@ export class Doc extends RefField {
             } else {
                 return Cast(layoutField, Doc, null);
             }
-            return Cast(self[renderFieldKey + '-layout[' + templateLayoutDoc[Id] + ']'], Doc, null) || templateLayoutDoc;
+            return Cast(self[renderFieldKey + '_layout[' + templateLayoutDoc[Id] + ']'], Doc, null) || templateLayoutDoc;
         }
         return undefined;
     }
@@ -701,7 +685,8 @@ export namespace Doc {
     }
 
     export function BestEmbedding(doc: Doc) {
-        const bestEmbedding = Doc.GetProto(doc) ? DocListCast(doc.proto_embeddings).find(doc => !doc.embedContainer && doc.author === Doc.CurrentUserEmail) : doc;
+        const bestEmbedding = Doc.GetProto(doc) ? [doc, ...DocListCast(doc.proto_embeddings)].find(doc => !doc.embedContainer && doc.author === Doc.CurrentUserEmail) : doc;
+        bestEmbedding && Doc.AddDocToList(Doc.GetProto(doc), 'protoEmbeddings', doc);
         return bestEmbedding ?? Doc.MakeEmbedding(doc);
     }
 
@@ -782,7 +767,6 @@ export namespace Doc {
         copy.cloneOf = doc;
         cloneMap.set(doc[Id], copy);
 
-        Doc.AddFileOrphan(copy);
         return copy;
     }
     export function repairClone(clone: Doc, cloneMap: Map<string, Doc>, visited: Set<Doc>) {
@@ -917,7 +901,7 @@ export namespace Doc {
         // If it doesn't find the expanded layout, then it makes a delegate of the template layout and
         // saves it on the data doc indexed by the template layout's id.
         //
-        const expandedLayoutFieldKey = templateField + '-layout[' + templateLayoutDoc[Id] + ']';
+        const expandedLayoutFieldKey = templateField + '_layout[' + templateLayoutDoc[Id] + ']';
         let expandedTemplateLayout = targetDoc?.[expandedLayoutFieldKey];
 
         if (templateLayoutDoc.resolvedDataDoc instanceof Promise) {
@@ -985,6 +969,59 @@ export namespace Doc {
         return overwrite;
     }
 
+    export function FindReferences(infield: Doc | List<any>, references: Set<Doc>, system: boolean | undefined) {
+        if (infield instanceof List<any>) {
+            infield.forEach(val => (val instanceof Doc || val instanceof List) && FindReferences(val, references, system));
+            return;
+        }
+        const doc = infield as Doc;
+        if (references.has(doc)) {
+            references.add(doc);
+            return;
+        }
+        const excludeLists = doc.title === 'My Recently Closed' || doc.title === 'My Header Bar' || doc.title === 'My Dashboards';
+        if (system !== undefined && ((system && !Doc.IsSystem(doc)) || (!system && Doc.IsSystem(doc)))) return;
+        references.add(doc);
+        Object.keys(doc).forEach(key => {
+            if (key === 'proto') {
+                if (doc.proto instanceof Doc) {
+                    Doc.FindReferences(doc.proto, references, system);
+                }
+            } else {
+                const cfield = ComputedField.WithoutComputed(() => FieldValue(doc[key]));
+                const field = key === 'author' ? Doc.CurrentUserEmail : ProxyField.WithoutProxy(() => doc[key]);
+                if (field instanceof RefField) {
+                    if (field instanceof Doc) {
+                        if (key === 'myLinkDatabase') {
+                            field instanceof Doc && references.add(field);
+                            // skip docs that have been closed and are scheduled for garbage collection
+                        } else {
+                            Doc.FindReferences(field, references, system);
+                        }
+                    }
+                } else if (cfield instanceof ComputedField) {
+                } else if (field instanceof ObjectField) {
+                    if (field instanceof Doc) {
+                        Doc.FindReferences(field, references, system);
+                    } else if (field instanceof List) {
+                        !excludeLists && Doc.FindReferences(field, references, system);
+                    } else if (field instanceof ProxyField) {
+                        if (key === 'myLinkDatabase') {
+                            field instanceof Doc && references.add(field);
+                            // skip docs that have been closed and are scheduled for garbage collection
+                        } else {
+                            Doc.FindReferences(field.value, references, system);
+                        }
+                    } else if (field instanceof PrefetchProxy) {
+                        Doc.FindReferences(field.value, references, system);
+                    }
+                } else if (field instanceof Promise) {
+                    debugger; //This shouldn't happend...
+                }
+            }
+        });
+    }
+
     export function MakeCopy(doc: Doc, copyProto: boolean = false, copyProtoId?: string, retitle = false): Doc {
         const copy = new Doc(copyProtoId, true);
         updateCachedAcls(copy);
@@ -1025,7 +1062,6 @@ export namespace Doc {
         if (retitle) {
             copy.title = incrementTitleCopy(StrCast(copy.title));
         }
-        Doc.AddFileOrphan(copy);
         return copy;
     }
 
@@ -1044,7 +1080,6 @@ export namespace Doc {
             if (!Doc.IsSystem(doc)) Doc.AddDocToList(doc[DocData], 'proto_embeddings', delegate);
             title && (delegate.title = title);
             delegate[Initializing] = false;
-            Doc.AddFileOrphan(delegate);
             return delegate;
         }
         return undefined;
@@ -1177,7 +1212,7 @@ export namespace Doc {
     // the document containing the view layout information - will be the Document itself unless the Document has
     // a layout field or 'layout' is given.
     export function Layout(doc: Doc, layout?: Doc): Doc {
-        const overrideLayout = layout && Cast(doc[`${StrCast(layout.isTemplateForField, 'data')}-layout[` + layout[Id] + ']'], Doc, null);
+        const overrideLayout = layout && Cast(doc[`${StrCast(layout.isTemplateForField, 'data')}_layout[` + layout[Id] + ']'], Doc, null);
         return overrideLayout || doc[DocLayout] || doc;
     }
     export function SetLayout(doc: Doc, layout: Doc | string) {
diff --git a/src/fields/FieldLoader.tsx b/src/fields/FieldLoader.tsx
index 2a7b936f7..a5a71833c 100644
--- a/src/fields/FieldLoader.tsx
+++ b/src/fields/FieldLoader.tsx
@@ -6,10 +6,9 @@ import './FieldLoader.scss';
 
 @observer
 export class FieldLoader extends React.Component {
-    @observable public static ServerLoadStatus = { requested: 0, retrieved: 0 };
-    public static active = false;
+    @observable public static ServerLoadStatus = { requested: 0, retrieved: 0, message: '' };
 
     render() {
-        return <div className="fieldLoader">{`Requested: ${FieldLoader.ServerLoadStatus.requested} ... ${FieldLoader.ServerLoadStatus.retrieved} `}</div>;
+        return <div className="fieldLoader">{`${FieldLoader.ServerLoadStatus.message} request: ${FieldLoader.ServerLoadStatus.requested} ... ${FieldLoader.ServerLoadStatus.retrieved} `}</div>;
     }
 }
diff --git a/src/server/DashUploadUtils.ts b/src/server/DashUploadUtils.ts
index 6764f2727..337bb812f 100644
--- a/src/server/DashUploadUtils.ts
+++ b/src/server/DashUploadUtils.ts
@@ -143,7 +143,6 @@ export namespace DashUploadUtils {
 
     export function uploadYoutube(videoId: string): Promise<Upload.FileResponse> {
         return new Promise<Upload.FileResponse<Upload.FileInformation>>((res, rej) => {
-            console.log('Uploading YouTube video: ' + videoId);
             const name = videoId;
             const path = name.replace(/^-/, '__') + '.mp4';
             const finalPath = serverPathToFile(Directory.videos, path);
@@ -523,7 +522,7 @@ export namespace DashUploadUtils {
             try {
                 const response = await axios.post(RESIZE_FUNCTION_URL, {
                     url: requestable,
-                    filename: resolved
+                    filename: resolved,
                 });
                 writtenFiles = response.data.writtenFiles;
             } catch (err) {
-- 
cgit v1.2.3-70-g09d2

