From ec1f159d60695a3cc89327561f7c60c00a06366d Mon Sep 17 00:00:00 2001
From: geireann <60007097+geireann@users.noreply.github.com>
Date: Mon, 13 Jul 2020 16:18:46 +0800
Subject: highlights, readjusted view, keyboard events

---
 src/client/views/nodes/FieldView.tsx | 1 +
 1 file changed, 1 insertion(+)

(limited to 'src/client/views/nodes/FieldView.tsx')

diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index c57738361..b1132ce33 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -45,6 +45,7 @@ export interface FieldViewProps {
     whenActiveChanged: (isActive: boolean) => void;
     dontRegisterView?: boolean;
     focus: (doc: Doc) => void;
+    presMultiSelect?: (doc: Doc) => void; //added for selecting multiple documents in a presentation
     ignoreAutoHeight?: boolean;
     PanelWidth: () => number;
     PanelHeight: () => number;
-- 
cgit v1.2.3-70-g09d2


From 8303cd6389fe9e3c861d7b429bb4e32d3417a895 Mon Sep 17 00:00:00 2001
From: Geireann Lindfield Roberts <60007097+geireann@users.noreply.github.com>
Date: Mon, 3 Aug 2020 02:58:31 +0800
Subject: Merge remote-tracking branch 'origin/menu_restructure' into
 presentation_updates

---
 package.json                                       |   6 +-
 src/Utils.ts                                       |   4 +-
 src/client/documents/DocumentTypes.ts              |   1 +
 src/client/documents/Documents.ts                  |  12 +
 src/client/util/CurrentUserUtils.ts                | 116 ++-
 src/client/util/GroupMemberView.scss               |   2 +-
 src/client/util/SelectionManager.ts                |   3 +
 src/client/util/SharingManager.tsx                 |   6 +-
 src/client/views/ContextMenuItem.tsx               |   4 +-
 src/client/views/DocumentButtonBar.tsx             |   8 +-
 src/client/views/DocumentDecorations.tsx           |  19 +-
 src/client/views/EditableView.tsx                  |   2 +-
 src/client/views/MainView.scss                     | 135 +++-
 src/client/views/MainView.tsx                      | 393 ++++++----
 src/client/views/PreviewCursor.tsx                 |   6 +-
 src/client/views/PropertiesButtons.scss            | 119 +++
 src/client/views/PropertiesButtons.tsx             | 598 ++++++++++++++
 .../views/collections/CollectionDockingView.scss   |  16 +-
 .../views/collections/CollectionDockingView.tsx    |  20 +-
 src/client/views/collections/CollectionMenu.tsx    |  79 +-
 .../views/collections/CollectionSchemaView.tsx     |   2 +-
 .../views/collections/CollectionStackingView.tsx   |   1 +
 .../CollectionStackingViewFieldColumn.tsx          |   2 +-
 src/client/views/collections/CollectionSubView.tsx |   2 +-
 .../views/collections/CollectionTreeView.tsx       |   7 +-
 src/client/views/collections/CollectionView.scss   |   1 +
 src/client/views/collections/CollectionView.tsx    |  11 +-
 .../views/collections/ParentDocumentSelector.tsx   |   6 +-
 src/client/views/collections/SchemaTable.tsx       |   8 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  12 +-
 .../collectionFreeForm/FormatShapePane.tsx         |  27 +-
 .../collectionFreeForm/PropertiesView.scss         | 620 +++++++++++++++
 .../collectionFreeForm/PropertiesView.tsx          | 858 +++++++++++++++++++++
 src/client/views/linking/LinkMenuItem.tsx          |   3 +-
 .../views/nodes/ContentFittingDocumentView.tsx     |   3 +
 src/client/views/nodes/DocumentContentsView.tsx    |   3 +-
 src/client/views/nodes/DocumentLinksButton.tsx     |   5 +-
 src/client/views/nodes/DocumentView.tsx            |  62 +-
 src/client/views/nodes/FieldView.tsx               |   1 +
 src/client/views/nodes/FontIconBox.scss            |   2 +-
 src/client/views/nodes/MenuIconBox.scss            |  49 ++
 src/client/views/nodes/MenuIconBox.tsx             |  33 +
 src/client/views/nodes/PresBox.tsx                 |  10 +-
 .../views/nodes/formattedText/DashFieldView.tsx    |   2 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx |   4 +-
 .../views/nodes/formattedText/RichTextMenu.tsx     |  41 +-
 src/client/views/nodes/formattedText/nodes_rts.ts  |   8 +-
 src/fields/Doc.ts                                  |   6 +-
 src/server/ActionUtilities.ts                      |  10 +-
 src/server/ApiManagers/UtilManager.ts              |   1 -
 src/server/DashUploadUtils.ts                      |  27 +-
 src/server/GarbageCollector.ts                     |   6 +-
 src/server/MemoryDatabase.ts                       |   5 +-
 src/server/Message.ts                              |   2 +-
 src/server/ProcessFactory.ts                       |   6 +-
 src/server/Recommender.ts                          | 133 ----
 src/server/RouteManager.ts                         |   8 +-
 src/server/Search.ts                               |   2 +-
 src/server/database.ts                             |   8 +-
 src/server/downsize.ts                             |   2 +-
 src/server/index.ts                                |  34 +-
 src/server/server_Initialization.ts                |  38 +-
 src/server/websocket.ts                            |  27 +-
 63 files changed, 3126 insertions(+), 521 deletions(-)
 create mode 100644 src/client/views/PropertiesButtons.scss
 create mode 100644 src/client/views/PropertiesButtons.tsx
 create mode 100644 src/client/views/collections/collectionFreeForm/PropertiesView.scss
 create mode 100644 src/client/views/collections/collectionFreeForm/PropertiesView.tsx
 create mode 100644 src/client/views/nodes/MenuIconBox.scss
 create mode 100644 src/client/views/nodes/MenuIconBox.tsx
 delete mode 100644 src/server/Recommender.ts

(limited to 'src/client/views/nodes/FieldView.tsx')

diff --git a/package.json b/package.json
index 11af6b2c6..420765e7c 100644
--- a/package.json
+++ b/package.json
@@ -11,8 +11,8 @@
     },
     "scripts": {
         "start-release": "cross-env RELEASE=true NODE_OPTIONS=--max_old_space_size=4096 ts-node-dev -- src/server/index.ts",
-        "start": "cross-env NODE_OPTIONS=--max_old_space_size=4096 ts-node-dev --transpile-only -- src/server/index.ts",
-        "oldstart": "cross-env NODE_OPTIONS=--max_old_space_size=4096 ts-node-dev -- src/server/index.ts",
+        "start": "cross-env NODE_OPTIONS=--max_old_space_size=4096 ts-node-dev --debug --transpile-only  -- src/server/index.ts",
+        "oldstart": "cross-env NODE_OPTIONS=--max_old_space_size=4096 ts-node-dev --debug -- src/server/index.ts",
         "debug": "cross-env NODE_OPTIONS=--max_old_space_size=8192 ts-node-dev --transpile-only --inspect -- src/server/index.ts",
         "build": "cross-env NODE_OPTIONS=--max_old_space_size=8192 webpack --env production",
         "test": "mocha -r ts-node/register test/**/*.ts",
@@ -260,4 +260,4 @@
         "xoauth2": "^1.2.0",
         "xregexp": "^4.3.0"
     }
-}
+}
\ No newline at end of file
diff --git a/src/Utils.ts b/src/Utils.ts
index a01a94134..0b057dc23 100644
--- a/src/Utils.ts
+++ b/src/Utils.ts
@@ -1,8 +1,8 @@
 import v4 = require('uuid/v4');
 import v5 = require("uuid/v5");
-import { Socket, Room } from 'socket.io';
-import { Message } from './server/Message';
 import { ColorState } from 'react-color';
+import { Socket } from 'socket.io';
+import { Message } from './server/Message';
 
 export namespace Utils {
     export let DRAG_THRESHOLD = 4;
diff --git a/src/client/documents/DocumentTypes.ts b/src/client/documents/DocumentTypes.ts
index 985fcce11..659f78970 100644
--- a/src/client/documents/DocumentTypes.ts
+++ b/src/client/documents/DocumentTypes.ts
@@ -13,6 +13,7 @@ export enum DocumentType {
     INK = "ink",        // ink stroke
     SCREENSHOT = "screenshot",  // view of a desktop application
     FONTICON = "fonticonbox",   // font icon
+    MENUICON = "menuiconbox",
     QUERY = "query",            // search query
     LABEL = "label",            // simple text label
     BUTTON = "button",          // onClick button
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 0da93aa7a..01cdb1eee 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -31,6 +31,7 @@ import { ColorBox } from "../views/nodes/ColorBox";
 import { ComparisonBox } from "../views/nodes/ComparisonBox";
 import { DocHolderBox } from "../views/nodes/DocHolderBox";
 import { FontIconBox } from "../views/nodes/FontIconBox";
+import { MenuIconBox } from "../views/nodes/MenuIconBox";
 import { FormattedTextBox } from "../views/nodes/formattedText/FormattedTextBox";
 import { ImageBox } from "../views/nodes/ImageBox";
 import { KeyValueBox } from "../views/nodes/KeyValueBox";
@@ -305,6 +306,13 @@ export namespace Docs {
                 layout: { view: FontIconBox, dataField: defaultDataKey },
                 options: { _width: 40, _height: 40, borderRounding: "100%" },
             }],
+            [DocumentType.MENUICON, {
+                layout: { view: MenuIconBox, dataField: defaultDataKey },
+            }],
+            // [DocumentType.RECOMMENDATION, {
+            //     layout: { view: RecommendationsBox, dataField: defaultDataKey },
+            //     options: { _width: 200, _height: 200 },
+            // }],
             [DocumentType.WEBCAM, {
                 layout: { view: DashWebRTCVideo, dataField: defaultDataKey }
             }],
@@ -791,6 +799,10 @@ export namespace Docs {
             return InstanceFromProto(Prototypes.get(DocumentType.FONTICON), undefined, { hideLinkButton: true, ...(options || {}) });
         }
 
+        export function MenuIconDocument(options?: DocumentOptions) {
+            return InstanceFromProto(Prototypes.get(DocumentType.MENUICON), undefined, { hideLinkButton: true, ...(options || {}) });
+        }
+
         export function PresElementBoxDocument(options?: DocumentOptions) {
             return InstanceFromProto(Prototypes.get(DocumentType.PRESELEMENT), undefined, { ...(options || {}) });
         }
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 6d752832a..b37c91c56 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -38,6 +38,16 @@ export class CurrentUserUtils {
     @observable public static GuestWorkspace: Doc | undefined;
     @observable public static GuestMobile: Doc | undefined;
 
+    @observable public static toolsBtn: any | undefined;
+    @observable public static libraryBtn: any | undefined;
+    @observable public static searchBtn: any | undefined;
+
+    @observable public static toolsStack: any | undefined;
+    @observable public static workspaceStack: any | undefined;
+    @observable public static catalogStack: any | undefined;
+    @observable public static closedStack: any | undefined;
+    @observable public static searchStack: any | undefined;
+
     // sets up the default User Templates - slideView, queryView, descriptionView
     static setupUserTemplateButtons(doc: Doc) {
         if (doc["template-button-query"] === undefined) {
@@ -492,6 +502,46 @@ export class CurrentUserUtils {
         return doc.myItemCreators as Doc;
     }
 
+    static menuBtnDescriptions(): {
+        title: string, icon: string, click: string,
+    }[] {
+        return [
+            { title: "Workspace", icon: "desktop", click: 'scriptContext.selectMenu("Workspace")' },
+            { title: "Catalog", icon: "file", click: 'scriptContext.selectMenu("Catalog")' },
+            { title: "Archive", icon: "archive", click: 'scriptContext.selectMenu("Archive")' },
+            { title: "Import", icon: "upload", click: 'scriptContext.selectMenu("Import")' },
+            { title: "Sharing", icon: "users", click: 'scriptContext.selectMenu("Sharing")' },
+            { title: "Tools", icon: "wrench", click: 'scriptContext.selectMenu("Tools")' },
+            { title: "Help", icon: "question-circle", click: 'scriptContext.selectMenu("Help")' },
+            { title: "Settings", icon: "cog", click: 'scriptContext.selectMenu("Settings")' },
+        ];
+    }
+
+    static setupMenuPanel(doc: Doc) {
+        if (doc.menuStack === undefined) {
+            const buttons = CurrentUserUtils.menuBtnDescriptions();
+            const menuBtns = buttons.map(({ title, icon, click }) => Docs.Create.MenuIconDocument({
+                icon,
+                title,
+                _backgroundColor: "black",
+                stayInCollection: true,
+                _width: 60,
+                _height: 60,
+                onClick: ScriptField.MakeScript(click, { scriptContext: "any" }),
+            }));
+
+            doc.menuStack = new PrefetchProxy(Docs.Create.StackingDocument(menuBtns, {
+                title: "menuItemPanel",
+                _backgroundColor: "black",
+                _gridGap: 0,
+                _yMargin: 0,
+                _yPadding: 0, _xMargin: 0, _autoHeight: false, _width: 60, _columnWidth: 60, lockedPosition: true, _chromeStatus: "disabled",
+            }));
+        }
+        return doc.menuStack as Doc;
+    }
+
+
     // Sets up mobile menu if it is undefined creates a new one, otherwise returns existing menu
     static setupActiveMobileMenu(doc: Doc) {
         if (doc.activeMobileMenu === undefined) {
@@ -601,6 +651,8 @@ export class CurrentUserUtils {
         const creatorBtns = await CurrentUserUtils.setupCreatorButtons(doc);
         const templateBtns = CurrentUserUtils.setupUserTemplateButtons(doc);
 
+        doc["tabs-button-tools"] = undefined;
+
         if (doc.myCreators === undefined) {
             doc.myCreators = new PrefetchProxy(Docs.Create.StackingDocument([creatorBtns, templateBtns], {
                 title: "all Creators", _yMargin: 0, _autoHeight: true, _xMargin: 0,
@@ -617,8 +669,11 @@ export class CurrentUserUtils {
 
         if (doc["tabs-button-tools"] === undefined) {
             const toolsStack = new PrefetchProxy(Docs.Create.StackingDocument([doc.myCreators as Doc, doc.myColorPicker as Doc], {
-                _width: 500, lockedPosition: true, _chromeStatus: "disabled", title: "tools stack", forceActive: true
+                _width: 500, lockedPosition: true, _chromeStatus: "disabled", hideFilterView: true, title: "tools stack", forceActive: true
             })) as any as Doc;
+
+            CurrentUserUtils.toolsStack = toolsStack;
+
             doc["tabs-button-tools"] = new PrefetchProxy(Docs.Create.ButtonDocument({
                 _width: 35, _height: 25, title: "Tools", _fontSize: "10pt",
                 letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)",
@@ -627,41 +682,63 @@ export class CurrentUserUtils {
                 dragFactory: toolsStack,
                 removeDropProperties: new List<string>(["lockedPosition"]),
                 stayInCollection: true,
+                hideFilterView: true,
                 targetContainer: new PrefetchProxy(sidebarContainer) as any as Doc,
                 onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel"),
             }));
         }
-        (doc["tabs-button-tools"] as Doc).sourcePanel; // prefetch sourcePanel
-        return doc["tabs-button-tools"] as Doc;
+        (doc["tabs-button-tools"] as any as Doc).sourcePanel; // prefetch sourcePanel
+
+        return doc["tabs-button-tools"] as any as Doc;
     }
 
     static setupWorkspaces(doc: Doc) {
         // setup workspaces library item
+        doc.myWorkspaces === undefined;
         if (doc.myWorkspaces === undefined) {
             doc.myWorkspaces = new PrefetchProxy(Docs.Create.TreeDocument([], {
-                title: "WORKSPACES", _height: 100, forceActive: true, boxShadow: "0 0", lockedPosition: true,
+                title: "WORKSPACES", _height: 100, forceActive: true, boxShadow: "0 0", lockedPosition: true, treeViewOpen: true,
             }));
         }
         const newWorkspace = ScriptField.MakeScript(`createNewWorkspace()`);
         (doc.myWorkspaces as Doc).contextMenuScripts = new List<ScriptField>([newWorkspace!]);
         (doc.myWorkspaces as Doc).contextMenuLabels = new List<string>(["Create New Workspace"]);
 
+        const workspaces = doc.myWorkspaces as Doc;
+
+        CurrentUserUtils.workspaceStack = new PrefetchProxy(Docs.Create.TreeDocument([workspaces], {
+            title: " ", _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "alias",
+            treeViewTruncateTitleWidth: 150, hideFilterView: true, treeViewPreventOpen: false, treeViewOpen: true,
+            lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true, targetDropAction: "same"
+        })) as any as Doc;
+
         return doc.myWorkspaces as Doc;
     }
     static setupCatalog(doc: Doc) {
+        doc.myCatalog === undefined;
         if (doc.myCatalog === undefined) {
             doc.myCatalog = new PrefetchProxy(Docs.Create.SchemaDocument([], [], {
                 title: "CATALOG", _height: 1000, _fitWidth: true, forceActive: true, boxShadow: "0 0", treeViewPreventOpen: false,
-                childDropAction: "alias", targetDropAction: "same", stayInCollection: true,
+                childDropAction: "alias", targetDropAction: "same", stayInCollection: true, treeViewOpen: true,
             }));
         }
+
+        const catalog = doc.myCatalog as Doc;
+
+        CurrentUserUtils.catalogStack = new PrefetchProxy(Docs.Create.TreeDocument([catalog], {
+            title: " ", _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "alias",
+            treeViewTruncateTitleWidth: 150, hideFilterView: true, treeViewPreventOpen: false, treeViewOpen: true,
+            lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true, targetDropAction: "same"
+        })) as any as Doc;
+
         return doc.myCatalog as Doc;
     }
     static setupRecentlyClosed(doc: Doc) {
         // setup Recently Closed library item
+        doc.myRecentlyClosed === undefined;
         if (doc.myRecentlyClosed === undefined) {
             doc.myRecentlyClosed = new PrefetchProxy(Docs.Create.TreeDocument([], {
-                title: "RECENTLY CLOSED", _height: 75, forceActive: true, boxShadow: "0 0", treeViewPreventOpen: true, stayInCollection: true,
+                title: "RECENTLY CLOSED", _height: 75, forceActive: true, boxShadow: "0 0", treeViewPreventOpen: false, treeViewOpen: true, stayInCollection: true,
             }));
         }
         // this is equivalent to using PrefetchProxies to make sure the recentlyClosed doc is ready
@@ -670,6 +747,14 @@ export class CurrentUserUtils {
         (doc.myRecentlyClosed as Doc).contextMenuScripts = new List<ScriptField>([clearAll!]);
         (doc.myRecentlyClosed as Doc).contextMenuLabels = new List<string>(["Clear All"]);
 
+        const recentlyClosed = doc.myRecentlyClosed as Doc;
+
+        CurrentUserUtils.closedStack = new PrefetchProxy(Docs.Create.TreeDocument([recentlyClosed], {
+            title: " ", _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "alias",
+            treeViewTruncateTitleWidth: 150, hideFilterView: true, treeViewPreventOpen: false, treeViewOpen: true,
+            lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true, targetDropAction: "same"
+        })) as any as Doc;
+
         return doc.myRecentlyClosed as Doc;
     }
     // setup the Library button which will display the library panel.  This panel includes a collection of workspaces, documents, and recently closed views
@@ -681,7 +766,7 @@ export class CurrentUserUtils {
         if (doc["tabs-button-library"] === undefined) {
             const libraryStack = new PrefetchProxy(Docs.Create.TreeDocument([workspaces, documents, recentlyClosed, doc], {
                 title: "Library", _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "alias",
-                treeViewTruncateTitleWidth: 150,
+                treeViewTruncateTitleWidth: 150, hideFilterView: true, treeViewPreventOpen: false,
                 lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true, targetDropAction: "same"
             })) as any as Doc;
             doc["tabs-button-library"] = new PrefetchProxy(Docs.Create.ButtonDocument({
@@ -701,6 +786,7 @@ export class CurrentUserUtils {
 
     // setup the Search button which will display the search panel.
     static setupSearchBtnPanel(doc: Doc, sidebarContainer: Doc) {
+        doc["tabs-button-search"] = undefined;
         if (doc["tabs-button-search"] === undefined) {
             doc["tabs-button-search"] = new PrefetchProxy(Docs.Create.ButtonDocument({
                 _width: 50, _height: 25, title: "Search", _fontSize: "10pt",
@@ -711,8 +797,9 @@ export class CurrentUserUtils {
                 lockedPosition: true,
                 onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel")
             }));
+            CurrentUserUtils.searchStack = new PrefetchProxy(Docs.Create.QueryDocument({ title: "search stack", })) as any as Doc;
         }
-        return doc["tabs-button-search"] as Doc;
+        return doc["tabs-button-search"] as any as Doc;
     }
 
     static setupSidebarContainer(doc: Doc) {
@@ -728,17 +815,17 @@ export class CurrentUserUtils {
     // setup the list of sidebar mode buttons which determine what is displayed in the sidebar
     static async setupSidebarButtons(doc: Doc) {
         const sidebarContainer = CurrentUserUtils.setupSidebarContainer(doc);
-        const toolsBtn = await CurrentUserUtils.setupToolsBtnPanel(doc, sidebarContainer);
-        const libraryBtn = CurrentUserUtils.setupLibraryPanel(doc, sidebarContainer);
-        const searchBtn = CurrentUserUtils.setupSearchBtnPanel(doc, sidebarContainer);
+        CurrentUserUtils.toolsBtn = await CurrentUserUtils.setupToolsBtnPanel(doc, sidebarContainer);
+        CurrentUserUtils.libraryBtn = CurrentUserUtils.setupLibraryPanel(doc, sidebarContainer);
+        CurrentUserUtils.searchBtn = CurrentUserUtils.setupSearchBtnPanel(doc, sidebarContainer);
 
         // Finally, setup the list of buttons to display in the sidebar
         if (doc["tabs-buttons"] === undefined) {
-            doc["tabs-buttons"] = new PrefetchProxy(Docs.Create.StackingDocument([libraryBtn, searchBtn, toolsBtn], {
+            doc["tabs-buttons"] = new PrefetchProxy(Docs.Create.StackingDocument([CurrentUserUtils.libraryBtn, CurrentUserUtils.searchBtn, CurrentUserUtils.toolsBtn], {
                 _width: 500, _height: 80, boxShadow: "0 0", _pivotField: "title", _columnsHideIfEmpty: true, ignoreClick: true, _chromeStatus: "view-mode",
                 title: "sidebar btn row stack", backgroundColor: "dimGray",
             }));
-            (toolsBtn.onClick as ScriptField).script.run({ this: toolsBtn });
+            (CurrentUserUtils.toolsBtn.onClick as ScriptField).script.run({ this: CurrentUserUtils.toolsBtn });
         }
     }
 
@@ -749,7 +836,7 @@ export class CurrentUserUtils {
     })) as any as Doc
 
     static ficon = (opts: DocumentOptions) => new PrefetchProxy(Docs.Create.FontIconDocument({
-        ...opts, dropAction: "alias", removeDropProperties: new List<string>(["dropAction"]), _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100
+        ...opts, dropAction: "alias", removeDropProperties: new List<string>(["dropAction"]), _nativeWidth: 40, _nativeHeight: 40, _width: 40, _height: 40
     })) as any as Doc
 
     /// sets up the default list of buttons to be shown in the expanding button menu at the bottom of the Dash window
@@ -855,6 +942,7 @@ export class CurrentUserUtils {
         this.setupDocTemplates(doc); // sets up the template menu of templates
         this.setupRightSidebar(doc);  // sets up the right sidebar collection for mobile upload documents and sharing
         this.setupActiveMobileMenu(doc); // sets up the current mobile menu for Dash Mobile
+        this.setupMenuPanel(doc);
         this.setupOverlays(doc);  // documents in overlay layer
         this.setupDockedButtons(doc);  // the bottom bar of font icons
         this.setupDefaultPresentation(doc); // presentation that's initially triggered
diff --git a/src/client/util/GroupMemberView.scss b/src/client/util/GroupMemberView.scss
index 2fc27ed03..2eb164988 100644
--- a/src/client/util/GroupMemberView.scss
+++ b/src/client/util/GroupMemberView.scss
@@ -44,7 +44,7 @@
             background: none;
 
             &:hover {
-                text-overflow: visible;
+                text-overflow: unset;
                 overflow-x: auto;
             }
         }
diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts
index 20d881961..05ba00331 100644
--- a/src/client/util/SelectionManager.ts
+++ b/src/client/util/SelectionManager.ts
@@ -12,6 +12,7 @@ export namespace SelectionManager {
 
         @observable IsDragging: boolean = false;
         SelectedDocuments: ObservableMap<DocumentView, boolean> = new ObservableMap();
+
         @action
         SelectDoc(docView: DocumentView, ctrlPressed: boolean): void {
 
@@ -32,6 +33,7 @@ export namespace SelectionManager {
         }
         @action
         DeselectDoc(docView: DocumentView): void {
+
             if (manager.SelectedDocuments.get(docView)) {
                 manager.SelectedDocuments.delete(docView);
                 docView.props.whenActiveChanged(false);
@@ -40,6 +42,7 @@ export namespace SelectionManager {
         }
         @action
         DeselectAll(): void {
+
             Array.from(manager.SelectedDocuments.keys()).map(dv => dv.props.whenActiveChanged(false));
             manager.SelectedDocuments.clear();
             Doc.UserDoc().activeSelection = new List<Doc>([]);
diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx
index 5896bdf92..000b3e46c 100644
--- a/src/client/util/SharingManager.tsx
+++ b/src/client/util/SharingManager.tsx
@@ -72,8 +72,6 @@ export default class SharingManager extends React.Component<{}> {
     @observable private showUserOptions: boolean = false; // whether to show individuals as options when sharing (in the react-select component)
     @observable private showGroupOptions: boolean = false; // // whether to show groups as options when sharing (in the react-select component)
 
-
-
     // private get linkVisible() {
     //     return this.sharingDoc ? this.sharingDoc[PublicKey] !== SharingPermissions.None : false;
     // }
@@ -148,7 +146,7 @@ export default class SharingManager extends React.Component<{}> {
         const members: string[] = JSON.parse(StrCast(group.members));
         const users: ValidatedUser[] = this.users.filter(({ user: { email } }) => members.includes(email));
 
-        const target = this.targetDoc!;
+        const target = targetDoc || this.targetDoc!;
         const ACL = `ACL-${StrCast(group.groupName)}`;
 
         target.author === Doc.CurrentUserEmail && distributeAcls(ACL, permission as SharingPermissions, target);
@@ -222,7 +220,7 @@ export default class SharingManager extends React.Component<{}> {
 
     setInternalSharing = (recipient: ValidatedUser, permission: string) => {
         const { user, notificationDoc } = recipient;
-        const target = this.targetDoc!;
+        const target = targetDoc || this.targetDoc!;
         const key = user.email.replace('.', '_');
         const ACL = `ACL-${key}`;
 
diff --git a/src/client/views/ContextMenuItem.tsx b/src/client/views/ContextMenuItem.tsx
index 81432968d..7e233ec04 100644
--- a/src/client/views/ContextMenuItem.tsx
+++ b/src/client/views/ContextMenuItem.tsx
@@ -80,7 +80,7 @@ export class ContextMenuItem extends React.Component<ContextMenuProps & { select
     render() {
         if ("event" in this.props) {
             return (
-                <div className={"contextMenu-item" + (this.props.selected ? " contextMenu-itemSelected" : "")} onClick={this.handleEvent}>
+                <div className={"contextMenu-item" + (this.props.selected ? " contextMenu-itemSelected" : "")} onPointerDown={this.handleEvent}>
                     {this.props.icon ? (
                         <span className="icon-background">
                             <FontAwesomeIcon icon={this.props.icon} size="sm" />
@@ -95,7 +95,7 @@ export class ContextMenuItem extends React.Component<ContextMenuProps & { select
             const where = !this.overItem ? "" : this._overPosY < window.innerHeight / 3 ? "flex-start" : this._overPosY > window.innerHeight * 2 / 3 ? "flex-end" : "center";
             const marginTop = !this.overItem ? "" : this._overPosY < window.innerHeight / 3 ? "20px" : this._overPosY > window.innerHeight * 2 / 3 ? "-20px" : "";
             const submenu = !this.overItem ? (null) :
-                <div className="contextMenu-subMenu-cont" style={{ marginLeft: "25%", left: "0px", marginTop }}>
+                <div className="contextMenu-subMenu-cont" style={{ marginLeft: "90%", left: "0px", marginTop }}>
                     {this._items.map(prop => <ContextMenuItem {...prop} key={prop.description} closeMenu={this.props.closeMenu} />)}
                 </div>;
             if (!("noexpand" in this.props)) {
diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index 6b85616c2..23a3e1684 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -281,7 +281,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
             {DocumentLinksButton.StartLink ? <div className="documentButtonBar-button">
                 <DocumentLinksButton links={this.view0.allLinks} View={this.view0} AlwaysOn={true} InMenu={true} StartLink={false} />
             </div> : null}
-            <div className="documentButtonBar-button">
+            {/* <div className="documentButtonBar-button">
                 {this.templateButton}
             </div>
             <div className="documentButtonBar-button">
@@ -289,16 +289,16 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
             </div>
             <div className="documentButtonBar-button">
                 {this.contextButton}
-            </div>
+            </div> */}
             <div className="documentButtonBar-button">
                 {this.pinButton}
             </div>
-            <div className="documentButtonBar-button" style={{ display: !considerPush ? "none" : "" }}>
+            {/* <div className="documentButtonBar-button" style={{ display: !considerPush ? "none" : "" }}>
                 {this.considerGoogleDocsPush}
             </div>
             <div className="documentButtonBar-button" style={{ display: !considerPull ? "none" : "" }}>
                 {this.considerGoogleDocsPull}
-            </div>
+            </div> */}
         </div>;
     }
 }
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 7fc4a5c99..dd5303904 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -1,5 +1,5 @@
 import { IconProp, library } from '@fortawesome/fontawesome-svg-core';
-import { faCaretUp, faFilePdf, faFilm, faImage, faObjectGroup, faStickyNote, faTextHeight, faArrowAltCircleDown, faArrowAltCircleUp, faCheckCircle, faCloudUploadAlt, faLink, faShare, faStopCircle, faSyncAlt, faTag, faTimes, faAngleLeft, faAngleRight, faAngleDoubleLeft, faAngleDoubleRight, faPause } from '@fortawesome/free-solid-svg-icons';
+import { faCaretUp, faFilePdf, faFilm, faImage, faObjectGroup, faStickyNote, faTextHeight, faArrowAltCircleDown, faArrowAltCircleUp, faCheckCircle, faCloudUploadAlt, faLink, faShare, faStopCircle, faSyncAlt, faTag, faTimes, faAngleLeft, faAngleRight, faAngleDoubleLeft, faAngleDoubleRight, faPause, faExternalLinkAlt } from '@fortawesome/free-solid-svg-icons';
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import { action, computed, observable, reaction, runInAction, get } from "mobx";
 import { observer } from "mobx-react";
@@ -47,6 +47,7 @@ library.add(faAngleDoubleRight);
 library.add(faAngleLeft);
 library.add(faAngleRight);
 library.add(faPause);
+library.add(faExternalLinkAlt);
 
 @observer
 export class DocumentDecorations extends React.Component<{}, { value: string }> {
@@ -533,12 +534,12 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
                 const ink = Cast(doc.data, InkField)?.inkData;
                 if (ink) {
                     const newPoints: { X: number, Y: number }[] = [];
-                    for (var i = 0; i < ink.length; i++) {
+                    ink.forEach(i => {
                         // (new x — oldx) + (oldxpoint * newWidt)/oldWidth 
-                        const newX = (doc.x - this._inkDocs[index].x) + (ink[i].X * doc._width) / this._inkDocs[index].width;
-                        const newY = (doc.y - this._inkDocs[index].y) + (ink[i].Y * doc._height) / this._inkDocs[index].height;
+                        const newX = ((doc.x || 0) - this._inkDocs[index].x) + (i.X * (doc._width || 0)) / this._inkDocs[index].width;
+                        const newY = ((doc.y || 0) - this._inkDocs[index].y) + (i.Y * (doc._height || 0)) / this._inkDocs[index].height;
                         newPoints.push({ X: newX, Y: newY });
-                    }
+                    });
                     doc.data = new InkField(newPoints);
 
                 }
@@ -617,9 +618,9 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
                 </div>}
             </> :
             <>
-                {minimal ? (null) : <Tooltip title={<><div className="dash-tooltip">Show context menu</div></>} placement="top"><div className="documentDecorations-contextMenu" key="menu" onPointerDown={this.onSettingsDown}>
-                    <FontAwesomeIcon size="lg" icon="cog" />
-                </div></Tooltip>}
+                {/* {minimal ? (null) : <Tooltip title={<><div className="dash-tooltip">Show context menu</div></>} placement="top"><div className="documentDecorations-contextMenu" key="menu" onPointerDown={this.onSettingsDown}>
+                    <FontAwesomeIcon size="lg" icon="bars" />
+                </div></Tooltip>} */}
                 <div className="documentDecorations-title" key="title" onPointerDown={this.onTitleDown} >
                     <span style={{ width: "100%", display: "inline-block", cursor: "move" }}>{`${this.selectionTitle}`}</span>
                 </div>
@@ -666,7 +667,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
                                 {"_"}
                             </div></Tooltip>}
                     <Tooltip title={<><div className="dash-tooltip">Open Document In Tab</div></>} placement="top"><div className="documentDecorations-openInTab" onPointerDown={this.onMaximizeDown}>
-                        {SelectionManager.SelectedDocuments().length === 1 ? DocumentDecorations.DocumentIcon(StrCast(seldoc.props.Document.layout, "...")) : "..."}
+                        {SelectionManager.SelectedDocuments().length === 1 ? <FontAwesomeIcon icon="external-link-alt" className="documentView-minimizedIcon" /> : "..."}
                     </div></Tooltip>
                     <div id="documentDecorations-rotation" className="documentDecorations-rotation"
                         onPointerDown={this.onRotateDown}> ⟲ </div>
diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx
index c7b149842..f9d060681 100644
--- a/src/client/views/EditableView.tsx
+++ b/src/client/views/EditableView.tsx
@@ -191,7 +191,7 @@ export class EditableView extends React.Component<EditableProps> {
             return (this.props.contents instanceof ObjectField ? (null) :
                 <div className={`editableView-container-editing${this.props.oneLine ? "-oneLine" : ""}`}
                     ref={this._ref}
-                    style={{ display: this.props.display, minHeight: "20px", height: `${this.props.height ? this.props.height : "auto"}`, maxHeight: `${this.props.maxHeight}` }}
+                    style={{ display: this.props.display, minHeight: "17px", whiteSpace: "nowrap", height: `${this.props.height ? this.props.height : "auto"}`, maxHeight: `${this.props.maxHeight}` }}
                     onClick={this.onClick} placeholder={this.props.placeholder}>
                     <span style={{
                         fontStyle: this.props.fontStyle, fontSize: this.props.fontSize,
diff --git a/src/client/views/MainView.scss b/src/client/views/MainView.scss
index e1ddbc533..054a409df 100644
--- a/src/client/views/MainView.scss
+++ b/src/client/views/MainView.scss
@@ -102,6 +102,44 @@
     user-select: none;
 }
 
+.mainView-propertiesDragger {
+    background-color: rgb(140, 139, 139);
+    height: 55px;
+    width: 15.5px;
+    position: absolute;
+    top: 55%;
+    border: 1px black solid;
+    border-radius: 0;
+    border-top-left-radius: 10px;
+    border-bottom-left-radius: 10px;
+    border-right: unset;
+    z-index: 2;
+
+    .mainView-propertiesDragger-icon {
+        width: 10px;
+        height: 10px;
+        float: left;
+        margin-left: 3px;
+        padding-top: 19px;
+    }
+
+    &:hover {
+        cursor: grab;
+    }
+}
+
+.mainiView-propertiesView {
+    display: flex;
+    flex-direction: column;
+    height: 100%;
+    position: absolute;
+    right: 0;
+    top: 0;
+    border-left: solid 1px;
+    z-index: 100000;
+    cursor: auto;
+}
+
 .mainView-flyoutContainer {
     display: flex;
     flex-direction: column;
@@ -114,6 +152,75 @@
     }
 }
 
+.mainView-menuPanel {
+
+    width: 60px;
+    background-color: black;
+    height: 100%;
+    //overflow-y: scroll;
+    //overflow-x: hidden;
+
+
+    .mainView-menuPanel-button {
+        padding: 7px;
+        padding-left: 7px;
+        width: 100%;
+
+        .mainView-menuPanel-button-wrap {
+            width: 45px;
+            /* padding: 5px; */
+            touch-action: none;
+            background: black;
+            transform-origin: top left;
+            /* margin-bottom: 5px; */
+            margin-top: 5px;
+            margin-right: 25px;
+            border-radius: 8px;
+
+            &:hover {
+                background: rgb(61, 61, 61);
+                cursor: pointer;
+            }
+        }
+    }
+
+    .mainView-menuPanel-button-label {
+        color: white;
+        margin-left: px;
+        margin-right: 4px;
+        border-radius: 8px;
+        width: 42px;
+        position: relative;
+        text-align: center;
+        font-size: 8px;
+        margin-top: 1px;
+        letter-spacing: normal;
+        padding: 3px;
+        background-color: inherit;
+    }
+
+    .mainView-menuPanel-button-icon {
+        width: auto;
+        height: 35px;
+        padding: 5px;
+    }
+
+    svg {
+        width: 95% !important;
+        height: 95%;
+    }
+}
+
+.mainView-searchPanel {
+    width: 100%;
+    height: 33px;
+    background-color: black;
+    color: white;
+    text-align: center;
+    vertical-align: middle;
+    padding-top: 6px;
+}
+
 .mainView-mainDiv {
     width: 100%;
     height: 100%;
@@ -162,26 +269,44 @@
     display: flex;
     flex-direction: column;
     z-index: 2;
+
+    .mainView-libraryFlyout-close {
+        right: 6;
+        top: 5;
+        position: absolute;
+        margin-right: 6px;
+        z-index: 10;
+        margin-bottom: 10;
+    }
 }
 
 .mainView-expandFlyoutButton {
     position: absolute;
-    top: 100px;
-    right: 30px;
+    top: 120px;
+    right: 55px;
     cursor: pointer;
 }
 
 .mainView-libraryHandle {
-    width: 20px;
+    width: 28px;
     left: calc(100% - 10px);
-    height: 40px;
+    height: 55px;
     top: 50%;
     border: 1px solid black;
-    border-radius: 5px;
+    border-radius: 8px;
     position: absolute;
     z-index: 2;
     touch-action: none;
     cursor: ew-resize;
+
+    .mainView-libraryHandle-icon {
+        width: 10px;
+        height: 10px;
+        float: right;
+        margin-right: 3px;
+        padding-top: 19px;
+    }
+
 }
 
 .mainView-workspace {
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 58478ce92..54b57a887 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -1,7 +1,6 @@
 import { library } from '@fortawesome/fontawesome-svg-core';
 import { faHireAHelper, faBuffer } from '@fortawesome/free-brands-svg-icons';
 import * as fa from '@fortawesome/free-solid-svg-icons';
-import { ANTIMODEMENU_HEIGHT } from './globalCssVariables.scss';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { action, computed, configure, observable, reaction, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
@@ -12,51 +11,55 @@ import { Doc, DocListCast, Field, Opt } from '../../fields/Doc';
 import { Id } from '../../fields/FieldSymbols';
 import { List } from '../../fields/List';
 import { listSpec } from '../../fields/Schema';
+import { ScriptField } from '../../fields/ScriptField';
 import { BoolCast, Cast, FieldValue, StrCast } from '../../fields/Types';
 import { TraceMobx } from '../../fields/util';
-import { CurrentUserUtils } from '../util/CurrentUserUtils';
-import { emptyFunction, emptyPath, returnFalse, returnOne, returnZero, returnTrue, Utils, returnEmptyFilter } from '../../Utils';
+import { emptyFunction, emptyPath, returnEmptyFilter, returnFalse, returnOne, returnTrue, returnZero, setupMoveUpEvents, Utils } from '../../Utils';
 import GoogleAuthenticationManager from '../apis/GoogleAuthenticationManager';
+import HypothesisAuthenticationManager from '../apis/HypothesisAuthenticationManager';
 import { DocServer } from '../DocServer';
 import { Docs, DocumentOptions } from '../documents/Documents';
 import { DocumentType } from '../documents/DocumentTypes';
+import { CurrentUserUtils } from '../util/CurrentUserUtils';
+import { DocumentManager } from '../util/DocumentManager';
+import GroupManager from '../util/GroupManager';
 import { HistoryUtil } from '../util/History';
-import RichTextMenu from './nodes/formattedText/RichTextMenu';
 import { Scripting } from '../util/Scripting';
+import { SelectionManager } from '../util/SelectionManager';
 import SettingsManager from '../util/SettingsManager';
-import GroupManager from '../util/GroupManager';
 import SharingManager from '../util/SharingManager';
+import { SnappingManager } from '../util/SnappingManager';
 import { Transform } from '../util/Transform';
+import { TimelineMenu } from './animationtimeline/TimelineMenu';
 import { CollectionDockingView } from './collections/CollectionDockingView';
+import FormatShapePane from "./collections/collectionFreeForm/FormatShapePane";
 import MarqueeOptionsMenu from './collections/collectionFreeForm/MarqueeOptionsMenu';
+import { PropertiesView } from './collections/collectionFreeForm/PropertiesView';
 import { CollectionLinearView } from './collections/CollectionLinearView';
+import CollectionMenu from './collections/CollectionMenu';
 import { CollectionView, CollectionViewType } from './collections/CollectionView';
 import { ContextMenu } from './ContextMenu';
 import { DictationOverlay } from './DictationOverlay';
 import { DocumentDecorations } from './DocumentDecorations';
 import GestureOverlay from './GestureOverlay';
+import { ANTIMODEMENU_HEIGHT } from './globalCssVariables.scss';
 import KeyManager from './GlobalKeyHandler';
+import { LinkMenu } from './linking/LinkMenu';
 import "./MainView.scss";
 import { MainViewNotifs } from './MainViewNotifs';
 import { AudioBox } from './nodes/AudioBox';
+import { DocumentLinksButton } from './nodes/DocumentLinksButton';
 import { DocumentView } from './nodes/DocumentView';
+import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox';
+import RichTextMenu from './nodes/formattedText/RichTextMenu';
+import { LinkDescriptionPopup } from './nodes/LinkDescriptionPopup';
+import { LinkDocPreview } from './nodes/LinkDocPreview';
 import { RadialMenu } from './nodes/RadialMenu';
+import { TaskCompletionBox } from './nodes/TaskCompletedBox';
 import { OverlayView } from './OverlayView';
 import PDFMenu from './pdf/PDFMenu';
 import { PreviewCursor } from './PreviewCursor';
-import { ScriptField } from '../../fields/ScriptField';
-import { TimelineMenu } from './animationtimeline/TimelineMenu';
-import { SnappingManager } from '../util/SnappingManager';
-import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox';
-import { DocumentManager } from '../util/DocumentManager';
-import { DocumentLinksButton } from './nodes/DocumentLinksButton';
-import { LinkMenu } from './linking/LinkMenu';
-import { LinkDocPreview } from './nodes/LinkDocPreview';
-import { TaskCompletionBox } from './nodes/TaskCompletedBox';
-import { LinkDescriptionPopup } from './nodes/LinkDescriptionPopup';
-import FormatShapePane from "./collections/collectionFreeForm/FormatShapePane";
-import HypothesisAuthenticationManager from '../apis/HypothesisAuthenticationManager';
-import CollectionMenu from './collections/CollectionMenu';
+import { undoBatch } from '../util/UndoManager';
 
 @observer
 export class MainView extends React.Component {
@@ -69,8 +72,8 @@ export class MainView extends React.Component {
 
     @observable private _panelWidth: number = 0;
     @observable private _panelHeight: number = 0;
-    @observable private _flyoutTranslate: boolean = true;
-    @observable public flyoutWidth: number = 250;
+    @observable private _flyoutTranslate: boolean = false;
+    @observable public flyoutWidth: number = 0;
     private get darkScheme() { return BoolCast(Cast(this.userDoc?.activeWorkspace, Doc, null)?.darkScheme); }
 
     @computed private get userDoc() { return Doc.UserDoc(); }
@@ -78,7 +81,27 @@ export class MainView extends React.Component {
     @computed public get mainFreeform(): Opt<Doc> { return (docs => (docs && docs.length > 1) ? docs[1] : undefined)(DocListCast(this.mainContainer!.data)); }
     @computed public get sidebarButtonsDoc() { return Cast(this.userDoc["tabs-buttons"], Doc) as Doc; }
 
+    @observable public sidebarContent: any = this.userDoc?.["tabs-panelContainer"];
+    @observable public panelContent: string = "none";
+    @observable public showProperties: boolean = false;
     public isPointerDown = false;
+    @computed get selectedDocumentView() {
+        if (SelectionManager.SelectedDocuments().length) {
+            return SelectionManager.SelectedDocuments()[0];
+        } else { return undefined; }
+    }
+
+    @observable _propertiesWidth: number = 0;
+    propertiesWidth = () => Math.max(0, Math.min(this._panelWidth - 50, this._propertiesWidth));
+
+    @computed get propertiesIcon() {
+        if (this.propertiesWidth() < 10) {
+            return "chevron-left";
+        } else {
+            return "chevron-right";
+        }
+    }
+    @observable propertiesDownX: number | undefined;
 
     componentDidMount() {
         DocServer.setPlaygroundFields(["dataTransition", "_viewTransition", "_panX", "_panY", "_viewScale", "_viewType", "_chromeStatus"]); // can play with these fields on someone else's
@@ -148,7 +171,10 @@ export class MainView extends React.Component {
             fa.faEye, fa.faArrowsAlt, fa.faQuoteLeft, fa.faSortAmountDown, fa.faAlignLeft, fa.faAlignCenter, fa.faAlignRight, fa.faHeading, fa.faRulerCombined,
             fa.faFillDrip, fa.faLink, fa.faUnlink, fa.faBold, fa.faItalic, fa.faChevronLeft, fa.faUnderline, fa.faStrikethrough, fa.faSuperscript, fa.faSubscript,
             fa.faIndent, fa.faEyeDropper, fa.faPaintRoller, fa.faBars, fa.faBrush, fa.faShapes, fa.faEllipsisH, fa.faHandPaper, fa.faMap, fa.faUser, faHireAHelper,
-            fa.faBezierCurve, fa.faCircle, fa.faLongArrowAltRight, fa.faPenFancy, fa.faAngleDoubleRight, fa.faAngleUp, fa.faAngleDown, fa.faPlayCircle, fa.faClock,
+            fa.faDesktop, fa.faTrashRestore, fa.faUsers, fa.faWrench, fa.faCog, fa.faMap, fa.faBellSlash, fa.faExpandAlt, fa.faArchive, fa.faBezierCurve, fa.faCircle,
+            fa.faLongArrowAltRight, fa.faPenFancy, fa.faAngleDoubleRight, faBuffer, fa.faExpand, fa.faUndo, fa.faSlidersH);
+        //Pres trail icons (just for the sake of merging)
+        library.add(fa.faAngleUp, fa.faAngleDown, fa.faPlayCircle, fa.faClock,
             fa.faRocket, fa.faExchangeAlt, faBuffer);
         this.initEventListeners();
         this.initAuthenticationRouters();
@@ -211,7 +237,7 @@ export class MainView extends React.Component {
         const freeformOptions: DocumentOptions = {
             x: 0,
             y: 400,
-            _width: this._panelWidth * .7,
+            _width: this._panelWidth * .7 - this.propertiesWidth(),
             _height: this._panelHeight,
             title: "Collection " + workspaceCount,
         };
@@ -277,16 +303,21 @@ export class MainView extends React.Component {
 
     @action
     onResize = (r: any) => {
-        this._panelWidth = r.offset.width;
+        this._panelWidth = r.offset.width;// - this.propertiesWidth();
         this._panelHeight = r.offset.height;
     }
-    getPWidth = () => this._panelWidth;
+
+    @action
+    getPWidth = () => this._panelWidth - this.propertiesWidth()
+
     getPHeight = () => this._panelHeight;
     getContentsHeight = () => this._panelHeight - this._buttonBarHeight;
 
-    defaultBackgroundColors = (doc: Doc) => {
+    defaultBackgroundColors = (doc: Opt<Doc>) => {
+        if (this.panelContent === doc?.title) return "lightgrey";
         if (this.darkScheme) {
             switch (doc?.type) {
+                case DocumentType.MENUICON: return "white";
                 case DocumentType.RTF || DocumentType.LABEL || DocumentType.BUTTON: return "#2d2d2d";
                 case DocumentType.LINK:
                 case DocumentType.COL: {
@@ -296,6 +327,7 @@ export class MainView extends React.Component {
             }
         } else {
             switch (doc?.type) {
+                case DocumentType.MENUICON: return "black";
                 case DocumentType.RTF: return "#f1efeb";
                 case DocumentType.BUTTON:
                 case DocumentType.LABEL: return "lightgray";
@@ -308,7 +340,8 @@ export class MainView extends React.Component {
         }
     }
     @computed get mainDocView() {
-        return <DocumentView Document={this.mainContainer!}
+        return <DocumentView
+            Document={this.mainContainer!}
             DataDoc={undefined}
             LibraryPath={emptyPath}
             addDocument={undefined}
@@ -324,7 +357,6 @@ export class MainView extends React.Component {
             NativeWidth={returnZero}
             PanelWidth={this.getPWidth}
             PanelHeight={this.getPHeight}
-            renderDepth={0}
             focus={emptyFunction}
             parentActive={returnTrue}
             whenActiveChanged={emptyFunction}
@@ -332,103 +364,63 @@ export class MainView extends React.Component {
             docFilters={returnEmptyFilter}
             ContainingCollectionView={undefined}
             ContainingCollectionDoc={undefined}
+            renderDepth={-1}
         />;
     }
     @computed get dockingContent() {
         TraceMobx();
         const mainContainer = this.mainContainer;
         const width = this.flyoutWidth;
-        return <Measure offset onResize={this.onResize}>
-            {({ measureRef }) =>
-                <div ref={measureRef} className="mainContent-div" onDrop={this.onDrop} style={{ width: `calc(100% - ${width}px)` }}>
-                    {!mainContainer ? (null) : this.mainDocView}
-                </div>
-            }
-        </Measure>;
-    }
-
-    _canClick = false;
-    onPointerDown = (e: React.PointerEvent) => {
-        if (this._flyoutTranslate) {
-            this._canClick = true;
-            this._flyoutSizeOnDown = e.clientX;
-            document.removeEventListener("pointermove", this.onPointerMove);
-            document.removeEventListener("pointerup", this.onPointerUp);
-            document.addEventListener("pointermove", this.onPointerMove);
-            document.addEventListener("pointerup", this.onPointerUp);
-            e.stopPropagation();
-            e.preventDefault();
-        }
+        return <div className="mainContent-div" onDrop={this.onDrop} style={{ width: `calc(100% - ${width}px)` }}>
+            {!mainContainer ? (null) : this.mainDocView}
+        </div>;
     }
 
     @action
-    pointerLeaveDragger = () => {
-        if (!this._flyoutTranslate) {
-            this.flyoutWidth = 0;
-            this._flyoutTranslate = true;
-        }
+    onPropertiesPointerDown = (e: React.PointerEvent) => {
+        setupMoveUpEvents(this, e, action((e: PointerEvent, down: number[], delta: number[]) => {
+            this._propertiesWidth = this._panelWidth - e.clientX;
+            return false;
+        }), returnFalse, action(() => this._propertiesWidth = this.propertiesWidth() < 15 ? Math.min(this._panelWidth - 50, 250) : 0), false);
     }
 
     @action
-    onPointerMove = (e: PointerEvent) => {
-        this.flyoutWidth = Math.max(e.clientX, 0);
-        Math.abs(this.flyoutWidth - this._flyoutSizeOnDown) > 6 && (this._canClick = false);
-        this.sidebarButtonsDoc._columnWidth = this.flyoutWidth / 3 - 30;
-    }
-    @action
-    onPointerUp = (e: PointerEvent) => {
-        if (Math.abs(e.clientX - this._flyoutSizeOnDown) < 4 && this._canClick) {
-            this.flyoutWidth = this.flyoutWidth < 15 ? 250 : 0;
-            this.flyoutWidth && (this.sidebarButtonsDoc._columnWidth = this.flyoutWidth / 3 - 30);
+    onFlyoutPointerDown = (e: React.PointerEvent) => {
+        this.panelContent = "none";
+        if (this._flyoutTranslate) {
+            setupMoveUpEvents(this, e, action((e: PointerEvent) => {
+                this.flyoutWidth = Math.max(e.clientX, 0);
+                this.sidebarButtonsDoc._columnWidth = this.flyoutWidth / 3 - 30;
+                return false;
+            }), emptyFunction, action(() => {
+                this.flyoutWidth = this.flyoutWidth < 15 ? 250 : 0;
+                this.flyoutWidth && (this.sidebarButtonsDoc._columnWidth = this.flyoutWidth / 3 - 30);
+            }));
         }
-        document.removeEventListener("pointermove", this.onPointerMove);
-        document.removeEventListener("pointerup", this.onPointerUp);
     }
+
     flyoutWidthFunc = () => this.flyoutWidth;
     addDocTabFunc = (doc: Doc, where: string, libraryPath?: Doc[]): boolean => {
         return where === "close" ? CollectionDockingView.CloseRightSplit(doc) :
             doc.dockingConfig ? this.openWorkspace(doc) :
                 CollectionDockingView.AddRightSplit(doc, libraryPath);
     }
-    sidebarScreenToLocal = () => new Transform(0, (RichTextMenu.Instance.Pinned ? -35 : 0) + (CollectionMenu.Instance.Pinned ? -35 : 0), 1);
+    sidebarScreenToLocal = () => new Transform(0, (CollectionMenu.Instance.Pinned ? -35 : 0), 1);
+    //sidebarScreenToLocal = () => new Transform(0, (RichTextMenu.Instance.Pinned ? -35 : 0) + (CollectionMenu.Instance.Pinned ? -35 : 0), 1);
     mainContainerXf = () => this.sidebarScreenToLocal().translate(0, -this._buttonBarHeight);
 
+    @computed get closePosition() { return 55 + this.flyoutWidth; }
     @computed get flyout() {
-        const sidebarContent = this.userDoc?.["tabs-panelContainer"];
-        if (!(sidebarContent instanceof Doc)) {
-            return (null);
-        }
-        return <div className="mainView-flyoutContainer" >
-            <div className="mainView-tabButtons" style={{ height: `${this._buttonBarHeight - 10/*margin-top*/}px`, backgroundColor: StrCast(this.sidebarButtonsDoc.backgroundColor) }}>
-                <DocumentView
-                    Document={this.sidebarButtonsDoc}
-                    DataDoc={undefined}
-                    LibraryPath={emptyPath}
-                    addDocument={undefined}
-                    rootSelected={returnTrue}
-                    addDocTab={this.addDocTabFunc}
-                    pinToPres={emptyFunction}
-                    removeDocument={undefined}
-                    onClick={undefined}
-                    ScreenToLocalTransform={this.sidebarScreenToLocal}
-                    ContentScaling={returnOne}
-                    NativeHeight={returnZero}
-                    NativeWidth={returnZero}
-                    PanelWidth={this.flyoutWidthFunc}
-                    PanelHeight={this.getPHeight}
-                    renderDepth={0}
-                    focus={emptyFunction}
-                    backgroundColor={this.defaultBackgroundColors}
-                    parentActive={returnTrue}
-                    whenActiveChanged={emptyFunction}
-                    bringToFront={emptyFunction}
-                    docFilters={returnEmptyFilter}
-                    ContainingCollectionView={undefined}
-                    ContainingCollectionDoc={undefined} />
-            </div>
-            <div className="mainView-contentArea" style={{ position: "relative", height: `calc(100% - ${this._buttonBarHeight}px)`, width: "100%", overflow: "visible" }}>
+        if (!this.sidebarContent) return null;
+        return <div className="mainView-libraryFlyout">
+            <div className="mainView-contentArea" style={{ position: "relative", height: `100%`, width: "100%", overflow: "visible" }}>
+                {this.flyoutWidth > 0 ? <div className="mainView-libraryFlyout-close"
+                    onPointerDown={this.closeFlyout}>
+                    <FontAwesomeIcon icon="times" color="black" size="sm" />
+                </div> : null}
+
                 <DocumentView
-                    Document={sidebarContent}
+                    Document={this.sidebarContent}
                     DataDoc={undefined}
                     LibraryPath={emptyPath}
                     addDocument={undefined}
@@ -451,52 +443,162 @@ export class MainView extends React.Component {
                     bringToFront={emptyFunction}
                     docFilters={returnEmptyFilter}
                     ContainingCollectionView={undefined}
-                    ContainingCollectionDoc={undefined} />
-                <div className="buttonContainer" >
-                    <button className="mainView-settings" key="settings" onClick={() => SettingsManager.Instance.open()}>
-                        <FontAwesomeIcon icon="cog" size="lg" />
-                    </button>
-                </div>
+                    ContainingCollectionDoc={undefined}
+                    relative={true}
+                />
             </div>
-            {this.docButtons}
+            {this.docButtons}</div>;
+    }
+
+    @computed get menuPanel() {
+
+        return <div className="mainView-menuPanel">
+            <DocumentView
+                Document={Doc.UserDoc().menuStack as Doc}
+                DataDoc={undefined}
+                LibraryPath={emptyPath}
+                addDocument={undefined}
+                addDocTab={this.addDocTabFunc}
+                pinToPres={emptyFunction}
+                NativeHeight={returnZero}
+                NativeWidth={returnZero}
+                rootSelected={returnTrue}
+                removeDocument={returnFalse}
+                onClick={undefined}
+                ScreenToLocalTransform={this.mainContainerXf}
+                ContentScaling={returnOne}
+                PanelWidth={() => 70}
+                PanelHeight={this.getContentsHeight}
+                renderDepth={0}
+                focus={emptyFunction}
+                backgroundColor={this.defaultBackgroundColors}
+                parentActive={returnTrue}
+                whenActiveChanged={emptyFunction}
+                bringToFront={emptyFunction}
+                docFilters={returnEmptyFilter}
+                ContainingCollectionView={undefined}
+                ContainingCollectionDoc={undefined}
+                relative={true}
+                scriptContext={this}
+            />
+        </div>;
+    }
+
+
+    @action @undoBatch
+    closeFlyout = () => {
+        this.panelContent = "none";
+        this.flyoutWidth = 0;
+    }
+
+    get groupManager() { return GroupManager.Instance; }
+
+    @action @undoBatch
+    selectMenu = (str: string) => {
+        if (this.panelContent === str && this.flyoutWidth !== 0) {
+            this.panelContent = "none";
+            this.flyoutWidth = 0;
+        } else {
+            this.panelContent = str;
+            switch (this.panelContent) {
+                case "Tools": this.sidebarContent.proto = CurrentUserUtils.toolsStack; break;
+                case "Workspace": this.sidebarContent.proto = CurrentUserUtils.workspaceStack; break;
+                case "Catalog": this.sidebarContent.proto = CurrentUserUtils.catalogStack; break;
+                case "Archive": this.sidebarContent.proto = CurrentUserUtils.closedStack; break;
+                case "Settings": this.sidebarContent.proto = SettingsManager.Instance.open(); break;
+                case "Sharing": this.sidebarContent.proto = GroupManager.Instance.open(); break;
+            }
+            if (str === "Settings" || str === "Sharing" || str === "Help") {
+                this.panelContent = "none";
+                this.flyoutWidth = 0;
+            } else {
+                MainView.expandFlyout();
+            }
+        }
+        return true;
+    }
+
+    @action @undoBatch
+    closeProperties = () => {
+        this._propertiesWidth = 0;
+    }
+
+    @computed get propertiesView() {
+        TraceMobx();
+        return <div className="mainView-propertiesView" style={{
+            overflow: this.propertiesWidth() < 15 ? "hidden" : undefined
+        }}>
+            <PropertiesView
+                width={this.propertiesWidth()}
+                height={this._panelHeight}
+                renderDepth={1}
+                ScreenToLocalTransform={Transform.Identity}
+                onDown={this.closeProperties}
+            />
         </div>;
     }
 
+    @computed get mainInnerContent() {
+        const rightFlyout = this.propertiesWidth() - 1;
+        return <>
+            {this.menuPanel}
+            <div style={{ display: "contents", flexDirection: "row", position: "relative" }}>
+                <div className="mainView-flyoutContainer" style={{ width: this.flyoutWidth }}>
+                    {this.flyoutWidth !== 0 ? <div className="mainView-libraryHandle"
+                        onPointerDown={this.onFlyoutPointerDown}
+                        style={{ backgroundColor: this.defaultBackgroundColors(undefined) }}>
+                        <span title="library View Dragger" style={{
+                            width: (this.flyoutWidth !== 0 && this._flyoutTranslate) ? "100%" : "3vw",
+                            //height: (this.flyoutWidth !== 0 && this._flyoutTranslate) ? "100%" : "100vh",
+                            position: (this.flyoutWidth !== 0 && this._flyoutTranslate) ? "absolute" : "fixed",
+                            top: (this.flyoutWidth !== 0 && this._flyoutTranslate) ? "" : "0"
+                        }} />
+                        <div className="mainview-libraryHandle-icon">
+                            <FontAwesomeIcon icon="chevron-left" color="black" size="sm" /> </div>
+                    </div> : null}
+                    <div className="mainView-libraryFlyout" style={{
+                        //transformOrigin: this._flyoutTranslate ? "" : "left center",
+                        transition: this._flyoutTranslate ? "" : "width .5s",
+                        //transform: `scale(${this._flyoutTranslate ? 1 : 0.8})`,
+                        boxShadow: this._flyoutTranslate ? "" : "rgb(156, 147, 150) 0.2vw 0.2vw 0.2vw"
+                    }}>
+                        {this.flyout}
+                        {this.expandButton}
+                    </div>
+                </div>
+                {this.dockingContent}
+                {this.showProperties ? (null) :
+                    <div className="mainView-propertiesDragger" title="Properties View Dragger" onPointerDown={this.onPropertiesPointerDown}
+                        style={{ right: rightFlyout, top: "45%" }}>
+                        <div className="mainView-propertiesDragger-icon">
+                            <FontAwesomeIcon icon={this.propertiesIcon} color="white" size="sm" /> </div>
+                    </div>
+                }
+                {this.propertiesWidth() < 10 ? (null) :
+                    <div style={{ width: this.propertiesWidth() }}> {this.propertiesView} </div>}
+            </div>
+        </>;
+    }
+
     @computed get mainContent() {
-        const sidebar = this.userDoc?.["tabs-panelContainer"];
-        const n = (RichTextMenu.Instance?.Pinned ? 1 : 0) + (CollectionMenu.Instance?.Pinned ? 1 : 0);
+        //const n = (RichTextMenu.Instance?.Pinned ? 1 : 0) + (CollectionMenu.Instance?.Pinned ? 1 : 0);
+        const n = (CollectionMenu.Instance?.Pinned ? 1 : 0);
         const height = `calc(100% - ${n * Number(ANTIMODEMENU_HEIGHT.replace("px", ""))}px)`;
-        return !this.userDoc || !(sidebar instanceof Doc) ? (null) : (
-            <div className="mainView-mainContent" style={{
-                color: this.darkScheme ? "rgb(205,205,205)" : "black",
-                //change to times 2 for both pinned
-                height,
-                width: (FormatShapePane.Instance?.Pinned) ? `calc(100% - 200px)` : "100%"
-            }} >
-                <div style={{ display: "contents", flexDirection: "row", position: "relative" }}>
-                    <div className="mainView-flyoutContainer" onPointerLeave={this.pointerLeaveDragger} style={{ width: this.flyoutWidth }}>
-                        <div className="mainView-libraryHandle" onPointerDown={this.onPointerDown}
-                            style={{ backgroundColor: this.defaultBackgroundColors(sidebar) }}>
-                            <span title="library View Dragger" style={{
-                                width: (this.flyoutWidth !== 0 && this._flyoutTranslate) ? "100%" : "3vw",
-                                //height: (this.flyoutWidth !== 0 && this._flyoutTranslate) ? "100%" : "100vh",
-                                position: (this.flyoutWidth !== 0 && this._flyoutTranslate) ? "absolute" : "fixed",
-                                top: (this.flyoutWidth !== 0 && this._flyoutTranslate) ? "" : "0"
-                            }} />
-                        </div>
-                        <div className="mainView-libraryFlyout" style={{
-                            //transformOrigin: this._flyoutTranslate ? "" : "left center",
-                            transition: this._flyoutTranslate ? "" : "width .5s",
-                            //transform: `scale(${this._flyoutTranslate ? 1 : 0.8})`,
-                            boxShadow: this._flyoutTranslate ? "" : "rgb(156, 147, 150) 0.2vw 0.2vw 0.8vw"
-                        }}>
-                            {this.flyout}
-                            {this.expandButton}
-                        </div>
+        const pinned = FormatShapePane.Instance?.Pinned;
+        const innerContent = this.mainInnerContent;
+        return !this.userDoc ? (null) : (
+            <Measure offset onResize={this.onResize}>
+                {({ measureRef }) =>
+                    <div className="mainView-mainContent" ref={measureRef} style={{
+                        color: this.darkScheme ? "rgb(205,205,205)" : "black",
+                        //change to times 2 for both pinned
+                        height,
+                        width: pinned ? `calc(100% - 200px)` : "100%"
+                    }} >
+                        {innerContent}
                     </div>
-                    {this.dockingContent}
-                </div>
-            </div>);
+                }
+            </Measure>);
     }
 
     public static expandFlyout = action(() => {
@@ -506,7 +608,7 @@ export class MainView extends React.Component {
     });
 
     @computed get expandButton() {
-        return !this._flyoutTranslate ? (<div className="mainView-expandFlyoutButton" title="Re-attach sidebar" onPointerDown={MainView.expandFlyout}><FontAwesomeIcon icon="chevron-right" color="grey" size="lg" /></div>) : (null);
+        return !this._flyoutTranslate ? (<div className="mainView-expandFlyoutButton" title="Re-attach sidebar" onPointerDown={MainView.expandFlyout}></div>) : (null);
     }
 
     addButtonDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((flg: boolean, doc) => flg && Doc.AddDocToList(Doc.UserDoc().dockedBtns as Doc, "data", doc), true);
@@ -600,8 +702,16 @@ export class MainView extends React.Component {
         </svg>;
     }
 
+    @computed get search() {
+        return <div className="mainView-searchPanel">
+            <div style={{ float: "left", marginLeft: "10px" }}>{Doc.CurrentUserEmail}</div>
+            <div>SEARCH GOES HERE</div>
+        </div>;
+    }
+
     render() {
         return (<div className={"mainView-container" + (this.darkScheme ? "-dark" : "")} ref={this._mainViewRef}>
+
             {this.inkResources}
             <DictationOverlay />
             <SharingManager />
@@ -610,9 +720,10 @@ export class MainView extends React.Component {
             <GoogleAuthenticationManager />
             <HypothesisAuthenticationManager />
             <DocumentDecorations />
+            {/* {this.search} */}
             <CollectionMenu />
             <FormatShapePane />
-            <RichTextMenu key="rich" />
+            <div style={{ display: "none" }}><RichTextMenu key="rich" /></div>
             {LinkDescriptionPopup.descriptionPopup ? <LinkDescriptionPopup /> : null}
             {DocumentLinksButton.EditLink ? <LinkMenu location={DocumentLinksButton.EditLinkLoc} docView={DocumentLinksButton.EditLink} addDocTab={DocumentLinksButton.EditLink.props.addDocTab} changeFlyout={emptyFunction} /> : (null)}
             {LinkDocPreview.LinkInfo ? <LinkDocPreview location={LinkDocPreview.LinkInfo.Location} backgroundColor={this.defaultBackgroundColors}
diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx
index b4116e980..d7034fcfb 100644
--- a/src/client/views/PreviewCursor.tsx
+++ b/src/client/views/PreviewCursor.tsx
@@ -112,10 +112,10 @@ export class PreviewCursor extends React.Component<{}> {
                 } else if (e.clipboardData.items.length) {
                     const batch = UndoManager.StartBatch("collection view drop");
                     const files: File[] = [];
-                    for (let i = 0; i < e.clipboardData.items.length; i++) {
-                        const file = e.clipboardData.items[i].getAsFile();
+                    Array.from(e.clipboardData.items).forEach(item => {
+                        const file = item.getAsFile();
                         file && files.push(file);
-                    }
+                    });
                     const generatedDocuments = await DocUtils.uploadFilesToDocs(files, { x: newPoint[0], y: newPoint[1] });
                     generatedDocuments.forEach(PreviewCursor._addDocument);
                     batch.end();
diff --git a/src/client/views/PropertiesButtons.scss b/src/client/views/PropertiesButtons.scss
new file mode 100644
index 000000000..e099122c4
--- /dev/null
+++ b/src/client/views/PropertiesButtons.scss
@@ -0,0 +1,119 @@
+@import "globalCssVariables";
+
+$linkGap : 3px;
+
+.propertiesButtons-linkFlyout {
+    grid-column: 2/4;
+}
+
+.propertiesButtons-linkButton-empty:hover {
+    background: $main-accent;
+    transform: scale(1.05);
+    cursor: pointer;
+}
+
+.propertiesButtons-linkButton-nonempty:hover {
+    background: $main-accent;
+    transform: scale(1.05);
+    cursor: pointer;
+}
+
+.propertiesButtons-linkButton-empty,
+.propertiesButtons-linkButton-nonempty {
+    height: 30px;
+    width: 30px;
+    border-radius: 5px;
+    opacity: 0.9;
+    pointer-events: auto;
+    background-color: #121721;
+    color: #fcfbf7;
+    text-transform: uppercase;
+    letter-spacing: 2px;
+    font-size: 75%;
+    transition: transform 0.2s;
+    text-align: center;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    margin-right: 10px;
+
+    &:hover {
+        background: $main-accent;
+        transform: scale(1.05);
+        cursor: pointer;
+    }
+}
+
+.propertiesButtons {
+    margin-top: $linkGap;
+    grid-column: 1/4;
+    width: max-content;
+    height: auto;
+    display: flex;
+    flex-direction: row;
+    overflow-x: visible;
+}
+
+.onClickFlyout-editScript {
+    text-align: center;
+    border: 0.5px solid grey;
+    background-color: rgb(230, 230, 230);
+    border-radius: 9px;
+    padding: 4px;
+}
+
+
+.propertiesButtons-button {
+    pointer-events: auto;
+    padding-right: 5px;
+    width: 25px;
+    border-radius: 5px;
+    margin-right: 18px;
+}
+
+.propertiesButtons-linker {
+    height: 30px;
+    width: 30px;
+    text-align: center;
+    border-radius: 5px;
+    pointer-events: auto;
+    color: $dark-color;
+    border: $dark-color 1px solid;
+    transition: 0.2s ease all;
+    margin-right: 5px;
+}
+
+.propertiesButtons-linker:hover {
+    cursor: pointer;
+    transform: scale(1.05);
+}
+
+
+@-moz-keyframes spin {
+    100% {
+        -moz-transform: rotate(360deg);
+    }
+}
+
+@-webkit-keyframes spin {
+    100% {
+        -webkit-transform: rotate(360deg);
+    }
+}
+
+@keyframes spin {
+    100% {
+        -webkit-transform: rotate(360deg);
+        transform: rotate(360deg);
+    }
+}
+
+@keyframes shadow-pulse {
+    0% {
+        box-shadow: 0 0 0 0px rgba(0, 0, 0, 0.8);
+    }
+
+    100% {
+        box-shadow: 0 0 0 10px rgba(0, 255, 0, 0);
+    }
+}
\ No newline at end of file
diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx
new file mode 100644
index 000000000..59e7cc7c8
--- /dev/null
+++ b/src/client/views/PropertiesButtons.tsx
@@ -0,0 +1,598 @@
+import { IconProp, library } from '@fortawesome/fontawesome-svg-core';
+import { faArrowAltCircleDown, faArrowAltCircleRight, faArrowAltCircleUp, faCheckCircle, faCloudUploadAlt, faLink, faPhotoVideo, faShare, faStopCircle, faSyncAlt, faTag, faTimes } from '@fortawesome/free-solid-svg-icons';
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { action, computed, observable, runInAction } from "mobx";
+import { observer } from "mobx-react";
+import { Doc, DocListCast } from "../../fields/Doc";
+import { RichTextField } from '../../fields/RichTextField';
+import { Cast, NumCast, BoolCast } from "../../fields/Types";
+import { emptyFunction, setupMoveUpEvents, Utils } from "../../Utils";
+import GoogleAuthenticationManager from '../apis/GoogleAuthenticationManager';
+import { Pulls, Pushes } from '../apis/google_docs/GoogleApiClientUtils';
+import { Docs, DocUtils } from '../documents/Documents';
+import { DragManager } from '../util/DragManager';
+import { CollectionDockingView, DockedFrameRenderer } from './collections/CollectionDockingView';
+import { ParentDocSelector } from './collections/ParentDocumentSelector';
+import './collections/ParentDocumentSelector.scss';
+import './PropertiesButtons.scss';
+import { MetadataEntryMenu } from './MetadataEntryMenu';
+import { DocumentView } from './nodes/DocumentView';
+import { GoogleRef } from "./nodes/formattedText/FormattedTextBox";
+import { TemplateMenu } from "./TemplateMenu";
+import { Template, Templates } from "./Templates";
+import React = require("react");
+import { Tooltip } from '@material-ui/core';
+import { SelectionManager } from '../util/SelectionManager';
+import SharingManager from '../util/SharingManager';
+import { GooglePhotos } from '../apis/google_docs/GooglePhotosClientUtils';
+import { ImageField } from '../../fields/URLField';
+import { undoBatch, UndoManager } from '../util/UndoManager';
+import { DocumentType } from '../documents/DocumentTypes';
+import { CollectionFreeFormView } from './collections/collectionFreeForm/CollectionFreeFormView';
+const higflyout = require("@hig/flyout");
+export const { anchorPoints } = higflyout;
+export const Flyout = higflyout.default;
+
+library.add(faLink);
+library.add(faTag);
+library.add(faTimes);
+library.add(faArrowAltCircleDown);
+library.add(faArrowAltCircleUp);
+library.add(faArrowAltCircleRight);
+library.add(faStopCircle);
+library.add(faCheckCircle);
+library.add(faCloudUploadAlt);
+library.add(faSyncAlt);
+library.add(faShare);
+library.add(faPhotoVideo);
+
+const cloud: IconProp = "cloud-upload-alt";
+const fetch: IconProp = "sync-alt";
+
+enum UtilityButtonState {
+    Default,
+    OpenRight,
+    OpenExternally
+}
+
+@observer
+export class PropertiesButtons extends React.Component<{}, {}> {
+    private _dragRef = React.createRef<HTMLDivElement>();
+    private _pullAnimating = false;
+    private _pushAnimating = false;
+    private _pullColorAnimating = false;
+
+    @observable private pushIcon: IconProp = "arrow-alt-circle-up";
+    @observable private pullIcon: IconProp = "arrow-alt-circle-down";
+    @observable private pullColor: string = "white";
+    @observable public isAnimatingFetch = false;
+    @observable public isAnimatingPulse = false;
+
+    @observable private openHover: UtilityButtonState = UtilityButtonState.Default;
+
+    @observable public static Instance: PropertiesButtons;
+    public static hasPushedHack = false;
+    public static hasPulledHack = false;
+
+
+    @computed get selectedDocumentView() {
+        if (SelectionManager.SelectedDocuments().length) {
+            return SelectionManager.SelectedDocuments()[0];
+        } else { return undefined; }
+    }
+    @computed get selectedDoc() { return this.selectedDocumentView?.rootDoc; }
+    @computed get dataDoc() { return this.selectedDocumentView?.dataDoc; }
+
+    @computed get onClick() { return this.selectedDoc?.onClickBehavior ? this.selectedDoc?.onClickBehavior : "nothing"; }
+
+    public startPullOutcome = action((success: boolean) => {
+        if (!this._pullAnimating) {
+            this._pullAnimating = true;
+            this.pullIcon = success ? "check-circle" : "stop-circle";
+            setTimeout(() => runInAction(() => {
+                this.pullIcon = "arrow-alt-circle-down";
+                this._pullAnimating = false;
+            }), 1000);
+        }
+    });
+
+    public startPushOutcome = action((success: boolean) => {
+        this.isAnimatingPulse = false;
+        if (!this._pushAnimating) {
+            this._pushAnimating = true;
+            this.pushIcon = success ? "check-circle" : "stop-circle";
+            setTimeout(() => runInAction(() => {
+                this.pushIcon = "arrow-alt-circle-up";
+                this._pushAnimating = false;
+            }), 1000);
+        }
+    });
+
+    public setPullState = action((unchanged: boolean) => {
+        this.isAnimatingFetch = false;
+        if (!this._pullColorAnimating) {
+            this._pullColorAnimating = true;
+            this.pullColor = unchanged ? "lawngreen" : "red";
+            setTimeout(this.clearPullColor, 1000);
+        }
+    });
+
+    private clearPullColor = action(() => {
+        this.pullColor = "white";
+        this._pullColorAnimating = false;
+    });
+
+    @computed
+    get considerGoogleDocsPush() {
+        const targetDoc = this.selectedDoc;
+        const published = targetDoc && Doc.GetProto(targetDoc)[GoogleRef] !== undefined;
+        const animation = this.isAnimatingPulse ? "shadow-pulse 1s linear infinite" : "none";
+        return !targetDoc ? (null) : <Tooltip title={<><div className="dash-tooltip">{`${published ? "Push" : "Publish"} to Google Docs`}</div></>}>
+            <div
+                className="propertiesButtons-linker"
+                style={{ animation }}
+                onClick={async () => {
+                    await GoogleAuthenticationManager.Instance.fetchOrGenerateAccessToken();
+                    !published && runInAction(() => this.isAnimatingPulse = true);
+                    PropertiesButtons.hasPushedHack = false;
+                    targetDoc[Pushes] = NumCast(targetDoc[Pushes]) + 1;
+                }}>
+                <FontAwesomeIcon className="documentdecorations-icon" icon={published ? (this.pushIcon as any) : cloud} size={published ? "sm" : "xs"} />
+            </div></Tooltip>;
+    }
+
+    @computed
+    get considerGoogleDocsPull() {
+        const targetDoc = this.selectedDoc;
+        const dataDoc = targetDoc && Doc.GetProto(targetDoc);
+        const animation = this.isAnimatingFetch ? "spin 0.5s linear infinite" : "none";
+
+        const title = (() => {
+            switch (this.openHover) {
+                default:
+                case UtilityButtonState.Default: return `${!dataDoc?.unchanged ? "Pull from" : "Fetch"} Google Docs`;
+                case UtilityButtonState.OpenRight: return "Open in Right Split";
+                case UtilityButtonState.OpenExternally: return "Open in new Browser Tab";
+            }
+        })();
+
+        return !targetDoc || !dataDoc || !dataDoc[GoogleRef] ? (null) : <Tooltip
+            title={<><div className="dash-tooltip">{title}</div></>}>
+            <div className="propertiesButtons-linker"
+                style={{ backgroundColor: this.pullColor }}
+                onPointerEnter={action(e => {
+                    if (e.altKey) {
+                        this.openHover = UtilityButtonState.OpenExternally;
+                    } else if (e.shiftKey) {
+                        this.openHover = UtilityButtonState.OpenRight;
+                    }
+                })}
+                onPointerLeave={action(() => this.openHover = UtilityButtonState.Default)}
+                onClick={async e => {
+                    const googleDocUrl = `https://docs.google.com/document/d/${dataDoc[GoogleRef]}/edit`;
+                    if (e.shiftKey) {
+                        e.preventDefault();
+                        let googleDoc = await Cast(dataDoc.googleDoc, Doc);
+                        if (!googleDoc) {
+                            const options = { _width: 600, _nativeWidth: 960, _nativeHeight: 800, isAnnotating: false, UseCors: false };
+                            googleDoc = Docs.Create.WebDocument(googleDocUrl, options);
+                            dataDoc.googleDoc = googleDoc;
+                        }
+                        CollectionDockingView.AddRightSplit(googleDoc);
+                    } else if (e.altKey) {
+                        e.preventDefault();
+                        window.open(googleDocUrl);
+                    } else {
+                        this.clearPullColor();
+                        PropertiesButtons.hasPulledHack = false;
+                        targetDoc[Pulls] = NumCast(targetDoc[Pulls]) + 1;
+                        dataDoc.unchanged && runInAction(() => this.isAnimatingFetch = true);
+                    }
+                }}>
+                <FontAwesomeIcon className="documentdecorations-icon" size="sm"
+                    style={{ WebkitAnimation: animation, MozAnimation: animation }}
+                    icon={(() => {
+                        switch (this.openHover) {
+                            default:
+                            case UtilityButtonState.Default: return dataDoc.unchanged === false ? (this.pullIcon as any) : fetch;
+                            case UtilityButtonState.OpenRight: return "arrow-alt-circle-right";
+                            case UtilityButtonState.OpenExternally: return "share";
+                        }
+                    })()}
+                />
+            </div></Tooltip>;
+    }
+    @computed
+    get pinButton() {
+        const targetDoc = this.selectedDoc;
+        const isPinned = targetDoc && Doc.isDocPinned(targetDoc);
+        return !targetDoc ? (null) : <Tooltip title={<><div className="dash-tooltip">{Doc.isDocPinned(targetDoc) ? "Unpin from presentation" : "Pin to presentation"}</div></>}>
+            <div className="propertiesButtons-linker"
+                style={{ backgroundColor: isPinned ? "white" : "rgb(37, 43, 51)", color: isPinned ? "black" : "white" }}
+                onClick={e => DockedFrameRenderer.PinDoc(targetDoc, isPinned)}>
+                <FontAwesomeIcon className="documentdecorations-icon" size="sm" icon="map-pin"
+                />
+            </div></Tooltip>;
+    }
+
+    @computed
+    get metadataButton() {
+        //const view0 = this.view0;
+        if (this.selectedDoc) {
+            return <Tooltip title={<><div className="dash-tooltip">Show metadata panel</div></>}>
+                <div className="propertiesButtons-linkFlyout">
+                    <Flyout anchorPoint={anchorPoints.LEFT_TOP}
+                        content={<MetadataEntryMenu docs={[this.selectedDoc]} suggestWithFunction />  /* tfs: @bcz This might need to be the data document? */}>
+                        <div className={"propertiesButtons-linkButton-" + "empty"} onPointerDown={e => e.stopPropagation()} >
+                            {<FontAwesomeIcon className="documentdecorations-icon" icon="tag" size="sm" />}
+                        </div>
+                    </Flyout>
+                </div></Tooltip>;
+        } else {
+            return null;
+        }
+
+    }
+
+    @observable _aliasDown = false;
+    onAliasButtonDown = (e: React.PointerEvent): void => {
+        setupMoveUpEvents(this, e, this.onAliasButtonMoved, emptyFunction, emptyFunction);
+    }
+    onAliasButtonMoved = () => {
+        if (this._dragRef.current) {
+            const dragDocView = this.selectedDocumentView!;
+            const dragData = new DragManager.DocumentDragData([dragDocView.props.Document]);
+            const [left, top] = dragDocView.props.ScreenToLocalTransform().inverse().transformPoint(0, 0);
+            dragData.dropAction = "alias";
+            DragManager.StartDocumentDrag([dragDocView.ContentDiv!], dragData, left, top, {
+                offsetX: dragData.offset[0],
+                offsetY: dragData.offset[1],
+                hideSource: false
+            });
+            return true;
+        }
+        return false;
+    }
+
+    @computed
+    get templateButton() {
+        const docView = this.selectedDocumentView;
+        const templates: Map<Template, boolean> = new Map();
+        const views = [this.selectedDocumentView];
+        Array.from(Object.values(Templates.TemplateList)).map(template =>
+            templates.set(template, views.reduce((checked, doc) => checked || doc?.props.Document["_show" + template.Name] ? true : false, false as boolean)));
+        return !docView ? (null) :
+            <Tooltip title={<><div className="dash-tooltip">Customize layout</div></>}>
+                <div className="propertiesButtons-linkFlyout">
+                    <Flyout anchorPoint={anchorPoints.LEFT_TOP} //onOpen={action(() => this._aliasDown = true)} onClose={action(() => this._aliasDown = false)}
+                        content={<TemplateMenu docViews={views.filter(v => v).map(v => v as DocumentView)} templates={templates} />}>
+                        <div className={"propertiesButtons-linkButton-empty"} >
+                            {<FontAwesomeIcon className="documentdecorations-icon" icon="edit" size="sm" />}
+                        </div>
+                    </Flyout>
+                </div></Tooltip>;
+    }
+
+    onCopy = () => {
+        if (this.selectedDoc && this.selectedDocumentView) {
+            const copy = Doc.MakeCopy(this.selectedDocumentView.props.Document, true);
+            copy.x = NumCast(this.selectedDoc.x) + NumCast(this.selectedDoc._width);
+            copy.y = NumCast(this.selectedDoc.y) + 30;
+            this.selectedDocumentView.props.addDocument?.(copy);
+        }
+    }
+
+    @computed
+    get copyButton() {
+        const targetDoc = this.selectedDoc;
+        return !targetDoc ? (null) : <Tooltip title={<><div className="dash-tooltip">{"Tap or Drag to create an alias"}</div></>}>
+            <div className={"propertiesButtons-linkButton-empty"}
+                ref={this._dragRef}
+                onPointerDown={this.onAliasButtonDown}
+                onClick={this.onCopy}>
+                {<FontAwesomeIcon className="documentdecorations-icon" icon="copy" size="sm" />}
+            </div>
+        </Tooltip>;
+    }
+
+    @action
+    onLock = () => {
+        this.selectedDocumentView?.toggleLockPosition();
+    }
+
+    @computed
+    get lockButton() {
+        const targetDoc = this.selectedDoc;
+        return !targetDoc ? (null) : <Tooltip
+            title={<><div className="dash-tooltip">{this.selectedDoc?.lockedPosition ?
+                "Unlock Position" : "Lock Position"}</div></>}>
+            <div className={"propertiesButtons-linkButton-empty"}
+                onPointerDown={this.onLock} >
+                {<FontAwesomeIcon className="documentdecorations-icon"
+                    icon={BoolCast(this.selectedDoc?.lockedPosition) ? "unlock" : "lock"} size="sm" />}
+            </div>
+        </Tooltip>;
+    }
+
+    @computed
+    get downloadButton() {
+        const targetDoc = this.selectedDoc;
+        return !targetDoc ? (null) : <Tooltip
+            title={<><div className="dash-tooltip">{"Download Document"}</div></>}>
+            <div className={"propertiesButtons-linkButton-empty"}
+                onPointerDown={async () => {
+                    if (this.selectedDocumentView?.props.Document) {
+                        Doc.Zip(this.selectedDocumentView?.props.Document);
+                    }
+                }}>
+                {<FontAwesomeIcon className="propertiesButtons-icon"
+                    icon="download" size="sm" />}
+            </div>
+        </Tooltip>;
+    }
+
+    @computed
+    get deleteButton() {
+        const targetDoc = this.selectedDoc;
+        return !targetDoc ? (null) : <Tooltip
+            title={<><div className="dash-tooltip">{"Delete Document"}</div></>}>
+            <div className={"propertiesButtons-linkButton-empty"}
+                onPointerDown={() => {
+                    this.selectedDocumentView?.props.ContainingCollectionView?.removeDocument(this.selectedDocumentView?.props.Document);
+                }}>
+                {<FontAwesomeIcon className="propertiesButtons-icon"
+                    icon="trash-alt" size="sm" />}
+            </div>
+        </Tooltip>;
+    }
+
+    @computed
+    get sharingButton() {
+        const targetDoc = this.selectedDoc;
+        return !targetDoc ? (null) : <Tooltip
+            title={<><div className="dash-tooltip">{"Share Document"}</div></>}>
+            <div className={"propertiesButtons-linkButton-empty"}
+                onPointerDown={() => {
+                    if (this.selectedDocumentView) {
+                        SharingManager.Instance.open(this.selectedDocumentView);
+                    }
+                }}>
+                {<FontAwesomeIcon className="propertiesButtons-icon"
+                    icon="users" size="sm" />}
+            </div>
+        </Tooltip>;
+    }
+
+    @computed
+    get onClickButton() {
+        if (this.selectedDoc) {
+            return <Tooltip title={<><div className="dash-tooltip">Choose onClick behavior</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="sm" />}
+                        </div>
+                    </Flyout>
+                </div></Tooltip>;
+        } else {
+            return null;
+        }
+    }
+
+    @action
+    handleOptionChange = (e: any) => {
+        const value = e.target.value;
+        this.selectedDoc && (this.selectedDoc.onClickBehavior = e.target.value);
+        if (value === "nothing") {
+            this.selectedDocumentView?.noOnClick();
+        } else if (value === "enterPortal") {
+            this.selectedDocumentView?.noOnClick();
+            this.selectedDocumentView?.makeIntoPortal();
+        } else if (value === "toggleDetail") {
+            this.selectedDocumentView?.noOnClick();
+            this.selectedDocumentView?.toggleDetail();
+        } else if (value === "linkInPlace") {
+            this.selectedDocumentView?.noOnClick();
+            this.selectedDocumentView?.toggleFollowLink("inPlace", true, false);
+        } else if (value === "linkOnRight") {
+            this.selectedDocumentView?.noOnClick();
+            this.selectedDocumentView?.toggleFollowLink("onRight", false, false);
+        }
+    }
+
+    @undoBatch @action
+    editOnClickScript = () => {
+        if (this.selectedDoc) {
+            DocUtils.makeCustomViewClicked(this.selectedDoc, undefined, "onClick");
+        }
+    }
+
+    @computed
+    get onClickFlyout() {
+        return <div><form>
+            <div className="radio">
+                <label>
+                    <input type="radio" value="nothing"
+                        checked={this.onClick === 'nothing'}
+                        onChange={this.handleOptionChange} />
+                    Select Document
+                </label>
+            </div>
+            <div className="radio">
+                <label>
+                    <input type="radio" value="enterPortal"
+                        checked={this.onClick === 'enterPortal'}
+                        onChange={this.handleOptionChange} />
+                    Enter Portal
+                </label>
+            </div>
+            <div className="radio">
+                <label>
+                    <input type="radio" value="toggleDetail"
+                        checked={this.onClick === 'toggleDetail'}
+                        onChange={this.handleOptionChange} />
+                    Toggle Detail
+                </label>
+            </div>
+            <div className="radio">
+                <label>
+                    <input type="radio" value="linkInPlace"
+                        checked={this.onClick === 'linkInPlace'}
+                        onChange={this.handleOptionChange} />
+                    Follow Link
+                </label>
+            </div>
+            <div className="radio">
+                <label>
+                    <input type="radio" value="linkOnRight"
+                        checked={this.onClick === 'linkOnRight'}
+                        onChange={this.handleOptionChange} />
+                    Open Link on Right
+                </label>
+            </div>
+        </form>
+            <div onPointerDown={this.editOnClickScript} className="onClickFlyout-editScript"> Edit onClick Script</div>
+        </div>;
+    }
+
+    @computed
+    get googlePhotosButton() {
+        const targetDoc = this.selectedDoc;
+        return !targetDoc ? (null) : <Tooltip
+            title={<><div className="dash-tooltip">{"Export to Google Photos"}</div></>}>
+            <div className={"propertiesButtons-linkButton-empty"}
+                onPointerDown={() => {
+                    if (this.selectedDocumentView) {
+                        GooglePhotos.Export.CollectionToAlbum({ collection: this.selectedDocumentView.Document }).then(console.log);
+                    }
+                }}>
+                {<FontAwesomeIcon className="documentdecorations-icon"
+                    icon="cloud-upload-alt" size="sm" />}
+            </div>
+        </Tooltip>;
+    }
+
+    @computed
+    get clustersButton() {
+        const targetDoc = this.selectedDoc;
+        return !targetDoc ? (null) : <Tooltip
+            title={<><div className="dash-tooltip">{this.selectedDoc?.useClusters ? "Stop Showing Clusters" : "Show Clusters"}</div></>}>
+            <div className={"propertiesButtons-linkButton-empty"}
+                style={{ backgroundColor: this.selectedDoc?.useClusters ? "#a0a0a0" : "" }}
+                onPointerDown={this.changeClusters}>
+                {<FontAwesomeIcon className="documentdecorations-icon"
+                    color={this.selectedDoc?.useClusters ? "black" : "white"}
+                    icon="braille" size="sm" />}
+            </div>
+        </Tooltip>;
+    }
+
+    @action @undoBatch
+    changeFitToBox = () => {
+        this.selectedDoc && (this.selectedDoc._fitToBox = !this.selectedDoc._fitToBox);
+    }
+
+    @action @undoBatch
+    changeClusters = () => {
+        this.selectedDoc && (this.selectedDoc.useClusters = !this.selectedDoc.useClusters);
+    }
+
+    @computed
+    get fitContentButton() {
+        const targetDoc = this.selectedDoc;
+        return !targetDoc ? (null) : <Tooltip
+            title={<><div className="dash-tooltip">{this.selectedDoc?._fitToBox ? "Stop Fitting Content" : "Fit Content"}</div></>}>
+            <div className={"propertiesButtons-linkButton-empty"}
+                style={{ backgroundColor: this.selectedDoc?._fitToBox ? "#a0a0a0" : "" }}
+                onPointerDown={this.changeFitToBox}>
+                {<FontAwesomeIcon className="documentdecorations-icon"
+                    color={this.selectedDoc?._fitToBox ? "black" : "white"}
+                    icon="expand" size="sm" />}
+            </div>
+        </Tooltip>;
+    }
+
+    // @computed
+    // get importButton() {
+    //     const targetDoc = this.selectedDoc;
+    //     return !targetDoc ? (null) : <Tooltip
+    //         title={<><div className="dash-tooltip">{"Import a Document"}</div></>}>
+    //         <div className={"propertiesButtons-linkButton-empty"}
+    //             onPointerDown={() => {
+    //                 if (this.selectedDocumentView) {
+    //                     CollectionFreeFormView.importDocument(100, 100);
+    //                 }
+    //             }}>
+    //             {<FontAwesomeIcon className="documentdecorations-icon"
+    //                 icon="upload" size="sm" />}
+    //         </div>
+    //     </Tooltip>;
+    // }
+
+
+    render() {
+        if (!this.selectedDoc) return (null);
+
+        const isText = this.selectedDoc[Doc.LayoutFieldKey(this.selectedDoc)] instanceof RichTextField;
+        const considerPull = isText && this.considerGoogleDocsPull;
+        const considerPush = isText && this.considerGoogleDocsPush;
+        const isImage = this.selectedDoc[Doc.LayoutFieldKey(this.selectedDoc)] instanceof ImageField;
+        const isCollection = this.selectedDoc.type === DocumentType.COL ? true : false;
+        const isFreeForm = this.selectedDoc._viewType === "freeform" ? true : false;
+
+        return <div><div className="propertiesButtons" style={{ paddingBottom: "5.5px" }}>
+            <div className="propertiesButtons-button">
+                {this.templateButton}
+            </div>
+            {/* <div className="propertiesButtons-button">
+                {this.metadataButton}
+            </div> */}
+            <div className="propertiesButtons-button">
+                {this.pinButton}
+            </div>
+            <div className="propertiesButtons-button">
+                {this.copyButton}
+            </div>
+            <div className="propertiesButtons-button">
+                {this.lockButton}
+            </div>
+            <div className="propertiesButtons-button">
+                {this.downloadButton}
+            </div>
+        </div>
+            <div className="propertiesButtons">
+                <div className="propertiesButtons-button">
+                    {this.deleteButton}
+                </div>
+                <div className="propertiesButtons-button">
+                    {this.onClickButton}
+                </div>
+                <div className="propertiesButtons-button">
+                    {this.sharingButton}
+                </div>
+                <div className="propertiesButtons-button" style={{ display: !considerPush ? "none" : "" }}>
+                    {this.considerGoogleDocsPush}
+                </div>
+                <div className="propertiesButtons-button" style={{ display: !considerPull ? "none" : "" }}>
+                    {this.considerGoogleDocsPull}
+                </div>
+                <div className="propertiesButtons-button" style={{ display: !isImage ? "none" : "" }}>
+                    {this.googlePhotosButton}
+                </div>
+                {/* <div className="propertiesButtons-button" style={{ display: !isCollection ? "none" : "" }}>
+                    {this.importButton}
+                </div> */}
+
+                <div className="propertiesButtons-button" style={{ display: !isFreeForm ? "none" : "" }}>
+                    {this.clustersButton}
+                </div>
+
+                <div className="propertiesButtons-button" style={{ display: !isFreeForm ? "none" : "" }}>
+                    {this.fitContentButton}
+                </div>
+
+            </div>
+        </div>;
+    }
+}
diff --git a/src/client/views/collections/CollectionDockingView.scss b/src/client/views/collections/CollectionDockingView.scss
index 9b14df760..6d93b2ba8 100644
--- a/src/client/views/collections/CollectionDockingView.scss
+++ b/src/client/views/collections/CollectionDockingView.scss
@@ -12,6 +12,7 @@
         width: 100%;
         height: 100%;
         position: absolute;
+
         .miniThumb {
             background: #25252525;
             position: absolute;
@@ -89,6 +90,7 @@
     transform: translate(0px, -3px);
     cursor: grab;
 }
+
 .lm_title.focus-visible {
     cursor: text;
 }
@@ -96,23 +98,25 @@
 .lm_title_wrap {
     overflow: hidden;
     height: 19px;
-    margin-top: -3px;
-    display:inline-block;
+    margin-top: -2px;
+    display: inline-block;
 }
+
 .lm_active .lm_title {
     border: solid 1px lightgray;
 }
+
 .lm_header .lm_tab .lm_close_tab {
     position: absolute;
     text-align: center;
 }
 
 .lm_header .lm_tab {
-    padding-right : 20px;
+    padding-right: 20px;
 }
 
 .lm_popout {
-    display:none;
+    display: none;
 }
 
 .messageCounter {
@@ -135,6 +139,7 @@
     position: absolute;
     top: 0;
     left: 0;
+
     // overflow: hidden;  // bcz: menus don't show up when this is on (e.g., the parentSelectorMenu)
     .collectionDockingView-gear {
         padding-left: 5px;
@@ -142,7 +147,10 @@
         width: 18px;
         display: inline-block;
         margin: auto;
+
+        display: none;
     }
+
     .collectionDockingView-dragAsDocument {
         touch-action: none;
         position: absolute;
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index f658e9816..d685fac4e 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -1,9 +1,8 @@
 import 'golden-layout/src/css/goldenlayout-base.css';
 import 'golden-layout/src/css/goldenlayout-dark-theme.css';
-import { action, computed, Lambda, observable, reaction, runInAction, trace } from "mobx";
+import { action, computed, Lambda, observable, reaction, runInAction, trace, IReactionDisposer } from "mobx";
 import { observer } from "mobx-react";
 import * as ReactDOM from 'react-dom';
-import Measure from "react-measure";
 import * as GoldenLayout from "../../../client/goldenLayout";
 import { DateField } from '../../../fields/DateField';
 import { Doc, DocListCast, Field, Opt, DataSym } from "../../../fields/Doc";
@@ -507,7 +506,6 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
 
             const doc = await DocServer.GetRefField(tab.contentItem.config.props.documentId) as Doc;
             if (doc instanceof Doc) {
-                //tab.titleElement[0].outerHTML = `<input class='lm_title' style="background:black" value='${doc.title}' />`;
                 tab.titleElement[0].onclick = (e: any) => tab.titleElement[0].focus();
                 tab.titleElement[0].onchange = (e: any) => {
                     tab.titleElement[0].size = e.currentTarget.value.length + 1;
@@ -522,6 +520,10 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
                 gearSpan.style.paddingLeft = "0px";
                 gearSpan.style.paddingRight = "12px";
                 const stack = tab.contentItem.parent;
+                tab.element[0].onpointerdown = (e: any) => {
+                    const view = DocumentManager.Instance.getDocumentView(doc);
+                    view && SelectionManager.SelectDoc(view, false);
+                };
                 // shifts the focus to this tab when another tab is dragged over it
                 tab.element[0].onmouseenter = (e: any) => {
                     if (!this._isPointerDown || !SnappingManager.GetIsDragging()) return;
@@ -676,10 +678,15 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
     @observable private _panelHeight = 0;
     @observable private _document: Opt<Doc>;
     @observable private _isActive: boolean = false;
+    _tabReaction: IReactionDisposer | undefined;
 
     get _stack(): any {
         return (this.props as any).glContainer.parent.parent;
     }
+    get _tab(): any {
+        const tab = (this.props as any).glContainer.tab.element[0] as HTMLElement;
+        return tab.getElementsByClassName("lm_title")?.[0];
+    }
     constructor(props: any) {
         super(props);
         DocServer.GetRefField(this.props.documentId).then(action((f: Opt<Field>) => this._document = f as Doc));
@@ -740,9 +747,16 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
         this.props.glContainer.layoutManager.on("activeContentItemChanged", this.onActiveContentItemChanged);
         this.props.glContainer.on("tab", this.onActiveContentItemChanged);
         this.onActiveContentItemChanged();
+        this._tabReaction = reaction(() => ({ views: SelectionManager.SelectedDocuments(), color: StrCast(this._document?._backgroundColor, "white") }),
+            (data) => {
+                const selected = data.views.some(v => Doc.AreProtosEqual(v.props.Document, this._document));
+                this._tab.style.backgroundColor = selected ? data.color : "";
+            }
+        );
     }
 
     componentWillUnmount() {
+        this._tabReaction?.();
         this.props.glContainer.layoutManager.off("activeContentItemChanged", this.onActiveContentItemChanged);
         this.props.glContainer.off("tab", this.onActiveContentItemChanged);
     }
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 0ca86172f..fdd1b4e81 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -25,6 +25,8 @@ import { SelectionManager } from "../../util/SelectionManager";
 import { DocumentView } from "../nodes/DocumentView";
 import { ColorState } from "react-color";
 import { ObjectField } from "../../../fields/ObjectField";
+import RichTextMenu from "../nodes/formattedText/RichTextMenu";
+import { RichTextField } from "../../../fields/RichTextField";
 import { ScriptField } from "../../../fields/ScriptField";
 import { IconProp } from '@fortawesome/fontawesome-svg-core';
 import { DocUtils } from "../../documents/Documents";
@@ -47,7 +49,7 @@ export default class CollectionMenu extends AntimodeMenu {
 
     componentDidMount() {
         reaction(() => SelectionManager.SelectedDocuments().length && SelectionManager.SelectedDocuments()[0],
-            (doc) => doc && this.SetSelection(doc))
+            (doc) => doc && this.SetSelection(doc));
     }
 
     @action
@@ -160,7 +162,8 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
         initialize: (button: Doc) => { button['target-docFilters'] = this.target._docFilters instanceof ObjectField ? ObjectField.MakeCopy(this.target._docFilters as any as ObjectField) : ""; },
     };
 
-    _freeform_commands = [this._viewCommand, this._saveFilterCommand, this._fitContentCommand, this._clusterCommand, this._contentCommand, this._templateCommand, this._narrativeCommand];
+    @computed get _freeform_commands() { return Doc.UserDoc().noviceMode ? [this._viewCommand, this._saveFilterCommand] : [this._viewCommand, this._saveFilterCommand, this._contentCommand, this._templateCommand, this._narrativeCommand]; }
+
     _stacking_commands = [this._contentCommand, this._templateCommand];
     _masonry_commands = [this._contentCommand, this._templateCommand];
     _schema_commands = [this._templateCommand, this._narrativeCommand];
@@ -308,18 +311,32 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
         </div>;
     }
 
+    @computed get selectedDocumentView() {
+        if (SelectionManager.SelectedDocuments().length) {
+            return SelectionManager.SelectedDocuments()[0];
+        } else { return undefined; }
+    }
+    @computed get selectedDoc() { return this.selectedDocumentView?.rootDoc; }
+    @computed get isText() {
+        if (this.selectedDoc) {
+            return this.selectedDoc[Doc.LayoutFieldKey(this.selectedDoc)] instanceof RichTextField;
+        }
+        else return false;
+    }
+
     render() {
         return (
             <div className="collectionMenu-cont" >
                 <div className="collectionMenu">
                     <div className="collectionViewBaseChrome">
-                        {this.props.type === CollectionViewType.Invalid || this.props.type === CollectionViewType.Docking ? (null) : this.viewModes}
-                        {this.props.type === CollectionViewType.Docking ? (null) : this.templateChrome}
-                        <div className="collectionViewBaseChrome-viewSpecs" title="filter documents to show" style={{ display: "grid" }}>
+                        {this.props.type === CollectionViewType.Invalid ||
+                            this.props.type === CollectionViewType.Docking || this.isText ? (null) : this.viewModes}
+                        {this.props.type === CollectionViewType.Docking || this.isText ? (null) : this.templateChrome}
+                        {/* <div className="collectionViewBaseChrome-viewSpecs" title="filter documents to show" style={{ display: "grid" }}>
                             <button className={"antimodeMenu-button"} onClick={this.toggleViewSpecs} >
                                 <FontAwesomeIcon icon="filter" size="lg" />
                             </button>
-                        </div>
+                        </div> */}
 
                         {this.props.docView.props.ContainingCollectionDoc?._viewType !== CollectionViewType.Freeform ? (null) : <button className={"antimodeMenu-button"} key="float"
                             style={{ backgroundColor: !this.props.docView.layoutDoc.isAnnotating ? "121212" : undefined, borderRight: "1px solid gray" }}
@@ -356,6 +373,20 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
     @computed get childDocs() {
         return DocListCast(this.dataField);
     }
+
+    @computed get selectedDocumentView() {
+        if (SelectionManager.SelectedDocuments().length) {
+            return SelectionManager.SelectedDocuments()[0];
+        } else { return undefined; }
+    }
+    @computed get selectedDoc() { return this.selectedDocumentView?.rootDoc; }
+    @computed get isText() {
+        if (this.selectedDoc) {
+            return this.selectedDoc[Doc.LayoutFieldKey(this.selectedDoc)] instanceof RichTextField;
+        }
+        else return false;
+    }
+
     @undoBatch
     @action
     nextKeyframe = (): void => {
@@ -384,6 +415,7 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
     miniMap = (): void => {
         this.document.hideMinimap = !this.document.hideMinimap;
     }
+
     private _palette = ["#D0021B", "#F5A623", "#F8E71C", "#8B572A", "#7ED321", "#417505", "#9013FE", "#4A90E2", "#50E3C2", "#B8E986", "#000000", "#4A4A4A", "#9B9B9B", "#FFFFFF", ""];
     private _width = ["1", "5", "10", "100"];
     // private _draw = ["⎯", "→", "↔︎", "∿", "↝", "↭", "ロ", "O", "∆"];
@@ -523,40 +555,44 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
     }
 
     @computed get formatPane() {
-        return <button className="antimodeMenu-button" key="format" title="toggle foramatting pane"
-            onPointerDown={action(e => FormatShapePane.Instance.Pinned = !FormatShapePane.Instance.Pinned)}
-            style={{ backgroundColor: this._fillBtn ? "121212" : "" }}>
-            <FontAwesomeIcon icon="angle-double-right" size="lg" />
-        </button>;
+        // return <button className="antimodeMenu-button" key="format" title="toggle foramatting pane"
+        //     onPointerDown={action(e => FormatShapePane.Instance.Pinned = !FormatShapePane.Instance.Pinned)}
+        //     style={{ backgroundColor: this._fillBtn ? "121212" : "" }}>
+        //     <FontAwesomeIcon icon="angle-double-right" size="lg" />
+        // </button>;
+        return null;
     }
 
     render() {
         return !this.props.docView.layoutDoc ? (null) : <div className="collectionFreeFormMenu-cont">
-            {this.props.docView.props.renderDepth !== 0 ? (null) :
+            {this.props.docView.props.renderDepth !== 0 || this.isText ? (null) :
                 <div key="map" title="mini map" className="backKeyframe" onClick={this.miniMap}>
                     <FontAwesomeIcon icon={"map"} size={"lg"} />
                 </div>
             }
-            <div key="back" title="back frame" className="backKeyframe" onClick={this.prevKeyframe}>
+            {!!!this.isText ? <div key="back" title="back frame" className="backKeyframe" onClick={this.prevKeyframe}>
                 <FontAwesomeIcon icon={"caret-left"} size={"lg"} />
-            </div>
-            <div key="num" title="toggle view all" className="numKeyframe" style={{ backgroundColor: this.document.editing ? "#759c75" : "#c56565" }}
+            </div> : null}
+            {!!!this.isText ? <div key="num" title="toggle view all" className="numKeyframe" style={{ backgroundColor: this.document.editing ? "#759c75" : "#c56565" }}
                 onClick={action(() => this.document.editing = !this.document.editing)} >
                 {NumCast(this.document.currentFrame)}
-            </div>
-            <div key="fwd" title="forward frame" className="fwdKeyframe" onClick={this.nextKeyframe}>
+            </div> : null}
+            {!!!this.isText ? <div key="fwd" title="forward frame" className="fwdKeyframe" onClick={this.nextKeyframe}>
                 <FontAwesomeIcon icon={"caret-right"} size={"lg"} />
-            </div>
+            </div> : null}
 
-            {!this.props.isOverlay || this.document.type !== DocumentType.WEB ? (null) :
+            {!this.props.isOverlay || this.document.type !== DocumentType.WEB || this.isText ? (null) :
                 <button className={"antimodeMenu-button"} key="hypothesis"
-                    style={{ backgroundColor: !this.props.docView.layoutDoc.isAnnotating ? "121212" : undefined, borderRight: "1px solid gray" }}
+                    style={{
+                        backgroundColor: !this.props.docView.layoutDoc.isAnnotating ? "121212" : undefined,
+                        borderRight: "1px solid gray"
+                    }}
                     title="Use Hypothesis"
                     onClick={() => this.props.docView.layoutDoc.isAnnotating = !this.props.docView.layoutDoc.isAnnotating}>
                     <FontAwesomeIcon icon={["fab", "hire-a-helper"]} size={"lg"} />
                 </button>
             }
-            {!this.props.isOverlay || this.props.docView.layoutDoc.isAnnotating ?
+            {(!this.props.isOverlay || this.props.docView.layoutDoc.isAnnotating) && !this.isText ?
                 <>
                     {this.drawButtons}
                     {this.widthPicker}
@@ -566,6 +602,7 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
                 </> :
                 (null)
             }
+            {this.isText ? <RichTextMenu key="rich" /> : null}
         </div>;
     }
 }
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index 5553bbbb7..f67e049fd 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -253,7 +253,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
             <div className="collectionSchema-headerMenu-group">
                 <div onClick={() => this.typesDropdownChange(!this._openTypes)}>
                     <label>Column type:</label>
-                    <FontAwesomeIcon icon={"caret-down"} size="sm" style={{ float: "right" }} />
+                    <FontAwesomeIcon icon={"caret-down"} size="lg" style={{ float: "right" }} />
                 </div>
                 {this._openTypes ? allColumnTypes : justColType}
             </div >
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 425dc90e4..a104ac011 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -227,6 +227,7 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument)
             addDocTab={this.addDocTab}
             bringToFront={returnFalse}
             ContentScaling={returnOne}
+            scriptContext={this.props.scriptContext}
             pinToPres={this.props.pinToPres}
         />;
     }
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index 26d2ee8a3..68c233a16 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -351,7 +351,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
             {this.props.parent.Document._columnsHideIfEmpty ? (null) : headingView}
             {
                 this.collapsed ? (null) :
-                    <div style={{ marginTop: 5 }}>
+                    <div>
                         <div key={`${heading}-stack`} className={`collectionStackingView-masonry${singleColumn ? "Single" : "Grid"}`}
                             style={{
                                 padding: singleColumn ? `${columnYMargin}px ${0}px ${style.yMargin}px ${0}px` : `${columnYMargin}px ${0}px`,
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 9f78c15eb..c90e85271 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -296,7 +296,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
                             const reg = new RegExp(Utils.prepend(""), "g");
                             const modHtml = srcUrl ? html.replace(reg, srcUrl) : html;
                             const htmlDoc = Docs.Create.HtmlDocument(modHtml, { ...options, title: "-web page-", _width: 300, _height: 300 });
-                            Doc.GetProto(htmlDoc)["data-text"] = Doc.GetProto(htmlDoc)["text"] = text;
+                            Doc.GetProto(htmlDoc)["data-text"] = Doc.GetProto(htmlDoc).text = text;
                             this.props.addDocument(htmlDoc);
                             if (srcWeb) {
                                 const focusNode = (SelectionManager.SelectedDocuments()[0].ContentDiv?.getElementsByTagName("iframe")[0].contentDocument?.getSelection()?.focusNode as any);
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index b8996c178..e5c4b9187 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -90,7 +90,10 @@ class TreeView extends React.Component<TreeViewProps> {
     get displayName() { return "TreeView(" + this.doc.title + ")"; }  // this makes mobx trace() statements more descriptive
     get defaultExpandedView() { return this.childDocs ? this.fieldKey : StrCast(this.doc.defaultExpandedView, this.noviceMode ? "layout" : "fields"); }
     @observable _overrideTreeViewOpen = false; // override of the treeViewOpen field allowing the display state to be independent of the document's state
-    set treeViewOpen(c: boolean) { if (this.props.treeViewPreventOpen) this._overrideTreeViewOpen = c; else this.doc.treeViewOpen = this._overrideTreeViewOpen = c; }
+    set treeViewOpen(c: boolean) {
+        if (this.props.treeViewPreventOpen) this._overrideTreeViewOpen = c;
+        else this.doc.treeViewOpen = this._overrideTreeViewOpen = c;
+    }
     @computed get treeViewOpen() { return (!this.props.treeViewPreventOpen && !this.doc.treeViewPreventOpen && BoolCast(this.doc.treeViewOpen)) || this._overrideTreeViewOpen; }
     @computed get treeViewExpandedView() { return StrCast(this.doc.treeViewExpandedView, this.defaultExpandedView); }
     @computed get MAX_EMBED_HEIGHT() { return NumCast(this.props.containingCollection.maxEmbedHeight, 200); }
@@ -101,7 +104,7 @@ class TreeView extends React.Component<TreeViewProps> {
         const layout = Doc.LayoutField(this.doc) instanceof Doc ? Doc.LayoutField(this.doc) as Doc : undefined;
         return ((this.props.dataDoc ? DocListCast(this.props.dataDoc[field]) : undefined) || // if there's a data doc for an expanded template, use it's data field
             (layout ? DocListCast(layout[field]) : undefined) || // else if there's a layout doc, display it's fields
-            DocListCast(this.doc[field])) as Doc[]; // otherwise use the document's data field
+            DocListCast(this.doc[field])); // otherwise use the document's data field
     }
     @computed get childDocs() { return this.childDocList(this.fieldKey); }
     @computed get childLinks() { return this.childDocList("links"); }
diff --git a/src/client/views/collections/CollectionView.scss b/src/client/views/collections/CollectionView.scss
index b630f9cf8..a5aef86de 100644
--- a/src/client/views/collections/CollectionView.scss
+++ b/src/client/views/collections/CollectionView.scss
@@ -24,6 +24,7 @@
         border-right: unset;
         z-index: 2;
     }
+
     .collectionTimeView-treeView {
         display: flex;
         flex-direction: column;
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 7e7ea6786..62e8dc26a 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -78,6 +78,7 @@ export interface CollectionViewCustomProps {
     childLayoutTemplate?: () => Opt<Doc>;  // specify a layout Doc template to use for children of the collection
     childLayoutString?: string;  // specify a layout string to use for children of the collection
     childOpacity?: () => number;
+    hideFilter?: true;
 }
 
 export interface CollectionRenderProps {
@@ -309,7 +310,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
 
             const options = cm.findByDescription("Options...");
             const optionItems = options && "subitems" in options ? options.subitems : [];
-            optionItems.splice(0, 0, { description: `${this.props.Document.forceActive ? "Select" : "Force"} Contents Active`, event: () => this.props.Document.forceActive = !this.props.Document.forceActive, icon: "project-diagram" });
+            !Doc.UserDoc().noviceMode ? optionItems.splice(0, 0, { description: `${this.props.Document.forceActive ? "Select" : "Force"} Contents Active`, event: () => this.props.Document.forceActive = !this.props.Document.forceActive, icon: "project-diagram" }) : null;
             if (this.props.Document.childLayout instanceof Doc) {
                 optionItems.push({ description: "View Child Layout", event: () => this.props.addDocTab(this.props.Document.childLayout as Doc, "onRight"), icon: "project-diagram" });
             }
@@ -368,7 +369,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
     get _facetWidth() { return NumCast(this.props.Document._facetWidth); }
     set _facetWidth(value) { this.props.Document._facetWidth = value; }
 
-    bodyPanelWidth = () => this.props.PanelWidth() - this.facetWidth();
+    bodyPanelWidth = () => this.props.PanelWidth();
     facetWidth = () => Math.max(0, Math.min(this.props.PanelWidth() - 25, this._facetWidth));
 
     @computed get dataDoc() {
@@ -490,6 +491,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
             return false;
         }), returnFalse, action(() => this._facetWidth = this.facetWidth() < 15 ? Math.min(this.props.PanelWidth() - 25, 200) : 0), false);
     }
+
     filterBackground = () => "rgba(105, 105, 105, 0.432)";
     get ignoreFields() { return ["_docFilters", "_docRangeFilters"]; } // this makes the tree view collection ignore these filters (otherwise, the filters would filter themselves)
     @computed get scriptField() {
@@ -559,6 +561,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
                 </div>
             </div>;
     }
+
     childLayoutTemplate = () => this.props.childLayoutTemplate?.() || Cast(this.props.Document.childLayoutTemplate, Doc, null);
     childLayoutString = this.props.childLayoutString || StrCast(this.props.Document.childLayoutString);
 
@@ -588,11 +591,11 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
                         Utils.CorsProxy(Cast(d.data, ImageField)!.url.href) : Cast(d.data, ImageField)!.url.href
                     :
                     ""))}
-            {(!this.props.isSelected() && !this.props.Document.forceActive) || this.props.Document.hideFilterView ? (null) :
+            {/* {(!this.props.isSelected() && !this.props.Document.forceActive) || this.props.Document.hideFilterView ? (null) :
                 <div className="collectionView-filterDragger" title="library View Dragger" onPointerDown={this.onPointerDown}
                     style={{ right: this.facetWidth() - 1, top: this.props.Document._viewType === CollectionViewType.Docking ? "25%" : "55%" }} />
             }
-            {this.facetWidth() < 10 ? (null) : this.filterView}
+            {this.facetWidth() < 10 ? (null) : this.filterView}  */}
         </div>);
     }
 }
diff --git a/src/client/views/collections/ParentDocumentSelector.tsx b/src/client/views/collections/ParentDocumentSelector.tsx
index 8c0b8de9d..532dd6abc 100644
--- a/src/client/views/collections/ParentDocumentSelector.tsx
+++ b/src/client/views/collections/ParentDocumentSelector.tsx
@@ -42,14 +42,14 @@ export class SelectorContextMenu extends React.Component<SelectorProps> {
     async fetchDocuments() {
         const aliases = (await SearchUtil.GetAliasesOfDocument(this.props.Document));
         const containerProtoSets = await Promise.all(aliases.map(async alias =>
-            await Promise.all((await SearchUtil.Search("", true, { fq: `data_l:"${alias[Id]}"` })).docs)));
+            ((await SearchUtil.Search("", true, { fq: `data_l:"${alias[Id]}"` })).docs)));
         const containerProtos = containerProtoSets.reduce((p, set) => { set.map(s => p.add(s)); return p; }, new Set<Doc>());
         const containerSets = await Promise.all(Array.from(containerProtos.keys()).map(async container => {
-            return (await SearchUtil.GetAliasesOfDocument(container));
+            return (SearchUtil.GetAliasesOfDocument(container));
         }));
         const containers = containerSets.reduce((p, set) => { set.map(s => p.add(s)); return p; }, new Set<Doc>());
         const doclayoutSets = await Promise.all(Array.from(containers.keys()).map(async (dp) => {
-            return (await SearchUtil.GetAliasesOfDocument(dp));
+            return (SearchUtil.GetAliasesOfDocument(dp));
         }));
         const doclayouts = Array.from(doclayoutSets.reduce((p, set) => { set.map(s => p.add(s)); return p; }, new Set<Doc>()).keys());
         runInAction(() => {
diff --git a/src/client/views/collections/SchemaTable.tsx b/src/client/views/collections/SchemaTable.tsx
index cde795098..7e2840c2c 100644
--- a/src/client/views/collections/SchemaTable.tsx
+++ b/src/client/views/collections/SchemaTable.tsx
@@ -148,7 +148,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
     }
 
     @action
-    changeTitleMode = () => this._showTitleDropdown = !this._showTitleDropdown;
+    changeTitleMode = () => this._showTitleDropdown = !this._showTitleDropdown
 
     @computed get borderWidth() { return Number(COLLECTION_BORDER_WIDTH); }
     @computed get tableColumns(): Column<Doc>[] {
@@ -208,7 +208,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
                 }}>
                 {col.heading}</div>;
 
-            const sortIcon = col.desc === undefined ? "circle" : col.desc === true ? "caret-down" : "caret-up";
+            const sortIcon = col.desc === undefined ? "caret-right" : col.desc === true ? "caret-down" : "caret-up";
 
             const header =
                 <div //className="collectionSchemaView-header"
@@ -224,12 +224,12 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
                         {keysDropdown}
                     </div>
                     <div onClick={e => this.changeSorting(col)}
-                        style={{ paddingRight: "6px", display: "inline" }}>
+                        style={{ paddingRight: "6px", marginLeft: "4px", display: "inline" }}>
                         <FontAwesomeIcon icon={sortIcon} size="sm" />
                     </div>
                     <div onClick={e => this.props.openHeader(col, e.clientX, e.clientY)}
                         style={{ float: "right", paddingRight: "6px" }}>
-                        <FontAwesomeIcon icon={"compass"} size="sm" />
+                        <FontAwesomeIcon icon={"cog"} size="sm" />
                     </div>
                 </div>;
 
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 151acb64d..109808956 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1145,7 +1145,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
     @action
     componentDidMount() {
         super.componentDidMount?.();
-        this._layoutComputeReaction = reaction(() => { TraceMobx(); return this.doLayoutComputation },
+        this._layoutComputeReaction = reaction(() => this.doLayoutComputation,
             (elements) => this._layoutElements = elements || [],
             { fireImmediately: true, name: "doLayout" });
 
@@ -1240,13 +1240,15 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
         const appearanceItems = appearance && "subitems" in appearance ? appearance.subitems : [];
         appearanceItems.push({ description: "Reset View", event: () => { this.props.Document._panX = this.props.Document._panY = 0; this.props.Document[this.scaleFieldKey] = 1; }, icon: "compress-arrows-alt" });
         appearanceItems.push({ description: `${this.fitToContent ? "Make Zoomable" : "Scale to Window"}`, event: () => this.Document._fitToBox = !this.fitToContent, icon: !this.fitToContent ? "expand-arrows-alt" : "compress-arrows-alt" });
-        appearanceItems.push({ description: "Arrange contents in grid", event: this.layoutDocsInGrid, icon: "table" });
+        !Doc.UserDoc().noviceMode ? appearanceItems.push({ description: "Arrange contents in grid", event: this.layoutDocsInGrid, icon: "table" }) : null;
         !appearance && ContextMenu.Instance.addItem({ description: "Appearance...", subitems: appearanceItems, icon: "eye" });
 
         const viewctrls = ContextMenu.Instance.findByDescription("UI Controls...");
         const viewCtrlItems = viewctrls && "subitems" in viewctrls ? viewctrls.subitems : [];
-        viewCtrlItems.push({ description: (Doc.UserDoc().showSnapLines ? "Hide" : "Show") + " Snap Lines", event: () => Doc.UserDoc().showSnapLines = !Doc.UserDoc().showSnapLines, icon: "compress-arrows-alt" });
-        viewCtrlItems.push({ description: (this.Document.useClusters ? "Hide" : "Show") + " Clusters", event: () => this.updateClusters(!this.Document.useClusters), icon: "braille" });
+
+
+        !Doc.UserDoc().noviceMode ? viewCtrlItems.push({ description: (Doc.UserDoc().showSnapLines ? "Hide" : "Show") + " Snap Lines", event: () => Doc.UserDoc().showSnapLines = !Doc.UserDoc().showSnapLines, icon: "compress-arrows-alt" }) : null;
+        !Doc.UserDoc().noviceMode ? viewCtrlItems.push({ description: (this.Document.useClusters ? "Hide" : "Show") + " Clusters", event: () => this.updateClusters(!this.Document.useClusters), icon: "braille" }) : null;
         !viewctrls && ContextMenu.Instance.addItem({ description: "UI Controls...", subitems: viewCtrlItems, icon: "eye" });
 
         const options = ContextMenu.Instance.findByDescription("Options...");
@@ -1291,7 +1293,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
                         setTimeout(() => {
                             SearchUtil.Search(`{!join from=id to=proto_i}id:link*`, true, {}).then(docs => {
                                 docs.docs.forEach(d => LinkManager.Instance.addLink(d));
-                            })
+                            });
                         }, 2000); // need to give solr some time to update so that this query will find any link docs we've added.
                     }
                 }
diff --git a/src/client/views/collections/collectionFreeForm/FormatShapePane.tsx b/src/client/views/collections/collectionFreeForm/FormatShapePane.tsx
index ddc282e57..6263be261 100644
--- a/src/client/views/collections/collectionFreeForm/FormatShapePane.tsx
+++ b/src/client/views/collections/collectionFreeForm/FormatShapePane.tsx
@@ -13,7 +13,6 @@ import AntimodeMenu from "../../AntimodeMenu";
 import "./FormatShapePane.scss";
 import { undoBatch } from "../../../util/UndoManager";
 import { ColorState, SketchPicker } from 'react-color';
-import { DocumentView } from "../../../views/nodes/DocumentView"
 
 @observer
 export default class FormatShapePane extends AntimodeMenu {
@@ -124,12 +123,12 @@ export default class FormatShapePane extends AntimodeMenu {
                     console.log(ink);
                     if (ink) {
                         const newPoints: { X: number, Y: number }[] = [];
-                        for (var j = 0; j < ink.length; j++) {
+                        ink.forEach(i => {
                             // (new x — oldx) + (oldxpoint * newWidt)/oldWidth 
-                            const newX = (doc.x - oldX) + (ink[j].X * doc._width) / oldWidth;
-                            const newY = (doc.y - oldY) + (ink[j].Y * doc._height) / oldHeight;
+                            const newX = ((doc.x || 0) - oldX) + (i.X * (doc._width || 0)) / oldWidth;
+                            const newY = ((doc.y || 0) - oldY) + (i.Y * (doc._height || 0)) / oldHeight;
                             newPoints.push({ X: newX, Y: newY });
-                        }
+                        });
                         doc.data = new InkField(newPoints);
                     }
                 }
@@ -148,12 +147,12 @@ export default class FormatShapePane extends AntimodeMenu {
                     console.log(ink);
                     if (ink) {
                         const newPoints: { X: number, Y: number }[] = [];
-                        for (var j = 0; j < ink.length; j++) {
+                        ink.forEach(i => {
                             // (new x — oldx) + (oldxpoint * newWidt)/oldWidth 
-                            const newX = (doc.x - oldX) + (ink[j].X * doc._width) / oldWidth;
-                            const newY = (doc.y - oldY) + (ink[j].Y * doc._height) / oldHeight;
+                            const newX = ((doc.x || 0) - oldX) + (i.X * (doc._width || 0)) / oldWidth;
+                            const newY = ((doc.y || 0) - oldY) + (i.Y * (doc._height || 0)) / oldHeight;
                             newPoints.push({ X: newX, Y: newY });
-                        }
+                        });
                         doc.data = new InkField(newPoints);
                     }
                 }
@@ -191,11 +190,11 @@ export default class FormatShapePane extends AntimodeMenu {
                 if (ink) {
 
                     const newPoints: { X: number, Y: number }[] = [];
-                    for (var i = 0; i < ink.length; i++) {
-                        const newX = Math.cos(angle) * (ink[i].X - _centerPoints[index].X) - Math.sin(angle) * (ink[i].Y - _centerPoints[index].Y) + _centerPoints[index].X;
-                        const newY = Math.sin(angle) * (ink[i].X - _centerPoints[index].X) + Math.cos(angle) * (ink[i].Y - _centerPoints[index].Y) + _centerPoints[index].Y;
+                    ink.forEach(i => {
+                        const newX = Math.cos(angle) * (i.X - _centerPoints[index].X) - Math.sin(angle) * (i.Y - _centerPoints[index].Y) + _centerPoints[index].X;
+                        const newY = Math.sin(angle) * (i.X - _centerPoints[index].X) + Math.cos(angle) * (i.Y - _centerPoints[index].Y) + _centerPoints[index].Y;
                         newPoints.push({ X: newX, Y: newY });
-                    }
+                    });
                     doc.data = new InkField(newPoints);
                     const xs = newPoints.map(p => p.X);
                     const ys = newPoints.map(p => p.Y);
@@ -395,12 +394,12 @@ export default class FormatShapePane extends AntimodeMenu {
     @computed get widInput() { return this.inputBox("wid", this.shapeWid, (val: string) => this.shapeWid = val); }
     @computed get rotInput() { return this.inputBoxDuo("rot", this.shapeRot, (val: string) => { this.rotate(Number(val) - Number(this.shapeRot)); this.shapeRot = val; return true; }, "∠:", "rot", this.shapeRot, (val: string) => this.shapeRot = val, ""); }
 
-    @computed get XpsInput() { return this.inputBoxDuo("Xps", this.shapeXps, (val: string) => this.shapeXps = val, "X:", "Yps", this.shapeYps, (val: string) => this.shapeYps = val, "Y:"); }
     @computed get YpsInput() { return this.inputBox("Yps", this.shapeYps, (val: string) => this.shapeYps = val); }
 
     @computed get controlPoints() { return this.controlPointsButton(); }
     @computed get lockRatio() { return this.lockRatioButton(); }
     @computed get rotate90() { return this.rotate90Button(); }
+    @computed get XpsInput() { return this.inputBoxDuo("Xps", this.shapeXps, (val: string) => this.shapeXps = val, "X:", "Yps", this.shapeYps, (val: string) => this.shapeYps = val, "Y:"); }
 
 
     @computed get propertyGroupItems() {
diff --git a/src/client/views/collections/collectionFreeForm/PropertiesView.scss b/src/client/views/collections/collectionFreeForm/PropertiesView.scss
new file mode 100644
index 000000000..74f32275a
--- /dev/null
+++ b/src/client/views/collections/collectionFreeForm/PropertiesView.scss
@@ -0,0 +1,620 @@
+.propertiesView {
+
+    background-color: rgb(205, 205, 205);
+    height: 100%;
+    font-family: "Noto Sans";
+    cursor: auto;
+
+    overflow-x: visible;
+    overflow-y: visible;
+
+    .propertiesView-title {
+        background-color: rgb(159, 159, 159);
+        text-align: center;
+        padding-top: 12px;
+        padding-bottom: 12px;
+        display: flex;
+        font-size: 18px;
+        font-weight: bold;
+        justify-content: center;
+
+        .propertiesView-title-icon {
+            width: 20px;
+            height: 20px;
+            padding-left: 38px;
+            margin-top: -5px;
+            right: 19;
+            position: absolute;
+
+            &:hover {
+                color: grey;
+                cursor: pointer;
+            }
+
+        }
+
+    }
+
+    .propertiesView-name {
+        border-bottom: 1px solid black;
+        padding: 8.5px;
+        font-size: 12.5px;
+
+        &:hover {
+            cursor: pointer;
+        }
+    }
+
+    .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);
+
+            .propertiesView-settings-title-icon {
+                float: right;
+                right: 0;
+                position: absolute;
+                margin-left: 2px;
+                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);
+
+            .propertiesView-sharing-title-icon {
+                float: right;
+                right: 0;
+                position: absolute;
+                margin-left: 2px;
+                margin-right: 9px;
+
+                &:hover {
+                    cursor: pointer;
+                }
+            }
+        }
+
+        .propertiesView-sharing-content {
+            font-size: 10px;
+            padding: 10px;
+            margin-left: 5px;
+        }
+    }
+
+    .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);
+
+            .propertiesView-appearance-title-icon {
+                float: right;
+                right: 0;
+                position: absolute;
+                margin-left: 2px;
+                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);
+
+            .propertiesView-transform-title-icon {
+                float: right;
+                right: 0;
+                position: absolute;
+                margin-left: 2px;
+                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;
+        margin-top: 2px;
+        margin-left: 3px;
+
+        .notify-button-icon {
+            width: 6px;
+            height: 6.5px;
+            margin-left: .5px;
+        }
+
+        &:hover {
+            background-color: rgb(158, 158, 158);
+            cursor: pointer;
+        }
+    }
+
+    .expansion-button-icon {
+        width: 11px;
+        height: 11px;
+        color: black;
+        margin-left: 27px;
+
+        &:hover {
+            color: rgb(131, 131, 131);
+            cursor: pointer;
+        }
+    }
+
+    .propertiesView-sharingTable {
+
+        border: 1px solid black;
+        padding: 5px;
+        border-radius: 6px;
+        /* width: 170px; */
+        margin-right: 10px;
+        background-color: #ececec;
+        max-height: 130px;
+        overflow-y: scroll;
+
+        .propertiesView-sharingTable-item {
+
+            display: flex;
+            padding: 3px;
+            align-items: center;
+            border-bottom: 0.5px solid grey;
+
+            &:hover .propertiesView-sharingTable-item-name {
+                overflow-x: unset;
+                white-space: unset;
+                overflow-wrap: break-word;
+            }
+
+            .propertiesView-sharingTable-item-name {
+                font-weight: bold;
+                width: 80px;
+                overflow-x: hidden;
+                display: inline-block;
+                text-overflow: ellipsis;
+                white-space: nowrap;
+            }
+
+            .propertiesView-sharingTable-item-permission {
+                display: flex;
+                right: 34;
+                float: right;
+                position: absolute;
+
+                .permissions-select {
+                    z-index: 1;
+                    border: none;
+                    background-color: inherit;
+                    width: 75px;
+                    text-align: justify; // for Edge
+                    text-align-last: end;
+
+                    &:hover {
+                        cursor: pointer;
+                    }
+                }
+            }
+
+            &:last-child {
+                border-bottom: none;
+            }
+        }
+    }
+
+    .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);
+
+            .propertiesView-fields-title-name {
+                font-size: 12.5px;
+                font-weight: bold;
+                white-space: nowrap;
+                width: 35px;
+                display: flex;
+            }
+
+            .propertiesView-fields-title-icon {
+                float: right;
+                right: 0;
+                position: absolute;
+                margin-left: 2px;
+                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;
+            }
+        }
+    }
+
+    .field {
+        display: flex;
+        font-size: 7px;
+        background-color: #e8e8e8;
+        padding-right: 3px;
+        border: 0.5px solid grey;
+        border-radius: 5px;
+        padding-left: 3px;
+    }
+
+    .uneditable-field {
+        display: flex;
+        overflow-y: visible;
+        margin-bottom: 2px;
+
+        &:hover {
+            cursor: auto;
+        }
+    }
+
+    .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);
+
+            .propertiesView-layout-title-icon {
+                float: right;
+                right: 0;
+                position: absolute;
+                margin-left: 2px;
+                margin-right: 9px;
+
+                &:hover {
+                    cursor: pointer;
+                }
+            }
+        }
+
+        .propertiesView-layout-content {
+            overflow: hidden;
+            padding: 10px;
+        }
+
+    }
+}
+
+.inking-button {
+
+    display: flex;
+
+    .inking-button-points {
+        background-color: #333333;
+        padding: 7px;
+        border-radius: 7px;
+        margin-right: 32px;
+        width: 32;
+        height: 32;
+        padding-top: 9px;
+        margin-left: 18px;
+
+        &:hover {
+            background: rgb(131, 131, 131);
+            transform: scale(1.05);
+            cursor: pointer;
+        }
+    }
+
+    .inking-button-lock {
+        background-color: #333333;
+        padding: 7px;
+        border-radius: 7px;
+        margin-right: 32px;
+        width: 32;
+        height: 32;
+        padding-top: 9px;
+        padding-left: 10px;
+
+        &:hover {
+            background: rgb(131, 131, 131);
+            transform: scale(1.05);
+            cursor: pointer;
+        }
+    }
+
+    .inking-button-rotate {
+        background-color: #333333;
+        padding: 7px;
+        border-radius: 7px;
+        width: 32;
+        height: 32;
+        padding-top: 9px;
+        padding-left: 10px;
+
+        &:hover {
+            background: rgb(131, 131, 131);
+            transform: scale(1.05);
+            cursor: pointer;
+        }
+    }
+}
+
+.inputBox-duo {
+    display: flex;
+}
+
+.inputBox {
+
+    margin-top: 10px;
+    display: flex;
+    height: 19px;
+    margin-right: 15px;
+
+    .inputBox-title {
+        font-size: 12px;
+        padding-right: 5px;
+    }
+
+    .inputBox-input {
+        font-size: 10px;
+        width: 50px;
+        margin-right: 1px;
+        border-radius: 3px;
+
+        &:hover {
+            cursor: pointer;
+        }
+    }
+
+    .inputBox-button {
+
+        .inputBox-button-up {
+            background-color: #333333;
+            height: 9px;
+            padding-left: 3px;
+            padding-right: 3px;
+            padding-top: 1px;
+            padding-bottom: 1px;
+            border-radius: 1.5px;
+
+            &:hover {
+                background: rgb(131, 131, 131);
+                transform: scale(1.05);
+                cursor: pointer;
+            }
+        }
+
+        .inputBox-button-down {
+            background-color: #333333;
+            height: 9px;
+            padding-left: 3px;
+            padding-right: 3px;
+            padding-top: 1px;
+            padding-bottom: 1px;
+            border-radius: 1.5px;
+
+            &:hover {
+                background: rgb(131, 131, 131);
+                transform: scale(1.05);
+                cursor: pointer;
+            }
+        }
+
+    }
+}
+
+.color-palette {
+    width: 160px;
+    height: 360;
+}
+
+.strokeAndFill {
+    display: flex;
+    margin-top: 10px;
+
+    .fill {
+        margin-right: 40px;
+        display: flex;
+        padding-bottom: 7px;
+        margin-left: 35px;
+
+        .fill-title {
+            font-size: 12px;
+            margin-right: 2px;
+        }
+
+        .fill-button {
+            padding-top: 2px;
+            margin-top: -1px;
+        }
+    }
+
+    .stroke {
+        display: flex;
+
+        .stroke-title {
+            font-size: 12px;
+        }
+
+        .stroke-button {
+            padding-top: 2px;
+            margin-left: 2px;
+            margin-top: -1px;
+        }
+    }
+}
+
+.widthAndDash {
+
+    .width {
+        .width-top {
+            display: flex;
+
+            .width-title {
+                font-size: 12;
+                margin-right: 20px;
+                margin-left: 35px;
+                text-align: center;
+            }
+
+            .width-input {
+                margin-right: 30px;
+                margin-top: -10px;
+            }
+        }
+
+        .width-range {
+            margin-right: 1px;
+            margin-bottom: 6;
+        }
+    }
+
+    .arrows {
+
+        display: flex;
+        margin-bottom: 3px;
+
+        .arrows-head {
+
+            display: flex;
+            margin-right: 35px;
+
+            .arrows-head-title {
+                font-size: 10;
+            }
+
+            .arrows-head-input {
+                margin-left: 6px;
+                margin-top: 2px;
+            }
+        }
+
+        .arrows-tail {
+            display: flex;
+
+            .arrows-tail-title {
+                font-size: 10;
+            }
+
+            .arrows-tail-input {
+                margin-left: 6px;
+                margin-top: 2px;
+            }
+        }
+    }
+
+    .dashed {
+
+        display: flex;
+        margin-left: 74px;
+        margin-bottom: 6px;
+
+        .dashed-title {
+            font-size: 10;
+        }
+
+        .dashed-input {
+            margin-left: 6px;
+            margin-top: 2px;
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/client/views/collections/collectionFreeForm/PropertiesView.tsx b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
new file mode 100644
index 000000000..35c7fd425
--- /dev/null
+++ b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
@@ -0,0 +1,858 @@
+import React = require("react");
+import { observer } from "mobx-react";
+import "./PropertiesView.scss";
+import { observable, action, computed, runInAction } from "mobx";
+import { Doc, Field, DocListCast, WidthSym, HeightSym, AclSym, AclPrivate, AclReadonly, AclAddonly, AclEdit, AclAdmin, Opt } from "../../../../fields/Doc";
+import { DocumentView } from "../../nodes/DocumentView";
+import { ComputedField } from "../../../../fields/ScriptField";
+import { EditableView } from "../../EditableView";
+import { KeyValueBox } from "../../nodes/KeyValueBox";
+import { Cast, NumCast, StrCast } from "../../../../fields/Types";
+import { listSpec } from "../../../../fields/Schema";
+import { ContentFittingDocumentView } from "../../nodes/ContentFittingDocumentView";
+import { returnFalse, returnOne, emptyFunction, emptyPath, returnTrue, returnZero, returnEmptyFilter, Utils } from "../../../../Utils";
+import { Id } from "../../../../fields/FieldSymbols";
+import { Transform } from "../../../util/Transform";
+import { PropertiesButtons } from "../../PropertiesButtons";
+import { SelectionManager } from "../../../util/SelectionManager";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { Tooltip, Checkbox, Divider } from "@material-ui/core";
+import SharingManager from "../../../util/SharingManager";
+import { DocumentType } from "../../../documents/DocumentTypes";
+import FormatShapePane from "./FormatShapePane";
+import { SharingPermissions, GetEffectiveAcl } from "../../../../fields/util";
+import { InkField } from "../../../../fields/InkField";
+import { undoBatch } from "../../../util/UndoManager";
+import { ColorState, SketchPicker } from "react-color";
+import AntimodeMenu from "../../AntimodeMenu";
+import "./FormatShapePane.scss";
+import { discovery_v1 } from "googleapis";
+import { PresBox } from "../../nodes/PresBox";
+import { DocumentManager } from "../../../util/DocumentManager";
+
+
+interface PropertiesViewProps {
+    width: number;
+    height: number;
+    renderDepth: number;
+    ScreenToLocalTransform: () => Transform;
+    onDown: (event: any) => void;
+}
+
+@observer
+export class PropertiesView extends React.Component<PropertiesViewProps> {
+
+    @computed get MAX_EMBED_HEIGHT() { return 200; }
+
+    @computed get selectedDocumentView() {
+        if (SelectionManager.SelectedDocuments().length) {
+            return SelectionManager.SelectedDocuments()[0];
+        } else if (PresBox.Instance) {
+            const presSlide = PresBox.Instance._selectedArray[0];
+            const view = DocumentManager.Instance.getDocumentView(presSlide);
+            if (view) return view;
+        } else { return undefined; }
+    }
+    @computed get selectedDoc() { return this.selectedDocumentView?.rootDoc; }
+    @computed get dataDoc() { return this.selectedDocumentView?.dataDoc; }
+
+    @observable layoutFields: boolean = false;
+
+    @observable openActions: boolean = true;
+    @observable openSharing: boolean = true;
+    @observable openFields: boolean = true;
+    @observable openLayout: boolean = true;
+    @observable openAppearance: boolean = true;
+    @observable openTransform: boolean = true;
+
+    @computed get isInk() { return this.selectedDoc?.type === DocumentType.INK; }
+
+    @action
+    rtfWidth = () => {
+        if (this.selectedDoc) {
+            return Math.min(this.selectedDoc?.[WidthSym](), this.props.width - 20);
+        } else {
+            return 0;
+        }
+    }
+    @action
+    rtfHeight = () => {
+        if (this.selectedDoc) {
+            return this.rtfWidth() <= this.selectedDoc?.[WidthSym]() ? Math.min(this.selectedDoc?.[HeightSym](), this.MAX_EMBED_HEIGHT) : this.MAX_EMBED_HEIGHT;
+        } else {
+            return 0;
+        }
+    }
+
+    @action
+    docWidth = () => {
+        if (this.selectedDoc) {
+            const layoutDoc = this.selectedDoc;
+            const aspect = NumCast(layoutDoc._nativeHeight, layoutDoc._fitWidth ? 0 : layoutDoc[HeightSym]()) / NumCast(layoutDoc._nativeWidth, layoutDoc._fitWidth ? 1 : layoutDoc[WidthSym]());
+            if (aspect) return Math.min(layoutDoc[WidthSym](), Math.min(this.MAX_EMBED_HEIGHT / aspect, this.props.width - 20));
+            return NumCast(layoutDoc._nativeWidth) ? Math.min(layoutDoc[WidthSym](), this.props.width - 20) : this.props.width - 20;
+        } else {
+            return 0;
+        }
+    }
+
+    @action
+    docHeight = () => {
+        if (this.selectedDoc && this.dataDoc) {
+            const layoutDoc = this.selectedDoc;
+            return Math.max(70, Math.min(this.MAX_EMBED_HEIGHT, (() => {
+                const aspect = NumCast(layoutDoc._nativeHeight, layoutDoc._fitWidth ? 0 : layoutDoc[HeightSym]()) / NumCast(layoutDoc._nativeWidth, layoutDoc._fitWidth ? 1 : layoutDoc[WidthSym]());
+                if (aspect) return this.docWidth() * aspect;
+                return layoutDoc._fitWidth ? (!this.dataDoc._nativeHeight ? NumCast(this.props.height) :
+                    Math.min(this.docWidth() * NumCast(layoutDoc.scrollHeight, NumCast(layoutDoc._nativeHeight)) / NumCast(layoutDoc._nativeWidth,
+                        NumCast(this.props.height)))) :
+                    NumCast(layoutDoc._height) ? NumCast(layoutDoc._height) : 50;
+            })()));
+        } else {
+            return 0;
+        }
+    }
+
+    @computed get expandedField() {
+        if (this.dataDoc && this.selectedDoc) {
+            const ids: { [key: string]: string } = {};
+            const doc = this.layoutFields ? Doc.Layout(this.selectedDoc) : this.dataDoc;
+            doc && Object.keys(doc).forEach(key => !(key in ids) && doc[key] !== ComputedField.undefined && (ids[key] = key));
+            const rows: JSX.Element[] = [];
+            for (const key of Object.keys(ids).slice().sort()) {
+                const contents = doc[key];
+                if (key[0] === "#") {
+                    rows.push(<div style={{ display: "flex", overflowY: "visible", marginBottom: "2px" }} key={key}>
+                        <span style={{ fontWeight: "bold", whiteSpace: "nowrap" }}>{key}</span>
+                    &nbsp;
+                </div>);
+                } else {
+                    let contentElement: (JSX.Element | null)[] | JSX.Element = [];
+                    contentElement = <EditableView key="editableView"
+                        contents={contents !== undefined ? Field.toString(contents as Field) : "null"}
+                        height={13}
+                        fontSize={10}
+                        GetValue={() => Field.toKeyValueString(doc, key)}
+                        SetValue={(value: string) => KeyValueBox.SetField(doc, key, value, true)}
+                    />;
+                    rows.push(<div style={{ display: "flex", overflowY: "visible", marginBottom: "-1px" }} key={key}>
+                        <span style={{ fontWeight: "bold", whiteSpace: "nowrap" }}>{key + ":"}</span>
+                        &nbsp;
+                        {contentElement}
+                    </div>);
+                }
+            }
+            rows.push(<div className="field" key={"newKeyValue"} style={{ marginTop: "3px" }}>
+                <EditableView
+                    key="editableView"
+                    contents={"add key:value or #tags"}
+                    height={13}
+                    fontSize={10}
+                    GetValue={() => ""}
+                    SetValue={this.setKeyValue} />
+            </div>);
+            return rows;
+        }
+    }
+
+    @computed get noviceFields() {
+        if (this.dataDoc && this.selectedDoc) {
+            const ids: { [key: string]: string } = {};
+            const doc = this.dataDoc;
+            doc && Object.keys(doc).forEach(key => !(key in ids) && doc[key] !== ComputedField.undefined && (ids[key] = key));
+            const rows: JSX.Element[] = [];
+            for (const key of Object.keys(ids).slice().sort()) {
+                if (key[0] === key[0].toUpperCase() || key[0] === "#" || key === "author" || key === "creationDate" || key.indexOf("lastModified") !== -1) {
+                    const contents = doc[key];
+                    if (key[0] === "#") {
+                        rows.push(<div className="uneditable-field" key={key}>
+                            <span style={{ fontWeight: "bold", whiteSpace: "nowrap" }}>{key}</span>
+                    &nbsp;
+                </div>);
+                    } else {
+                        const value = Field.toString(contents as Field);
+                        if (key === "author" || key === "creationDate" || key.indexOf("lastModified") !== -1) {
+                            rows.push(<div className="uneditable-field" key={key}>
+                                <span style={{ fontWeight: "bold", whiteSpace: "nowrap" }}>{key + ": "}</span>
+                                <div style={{ whiteSpace: "nowrap", overflowX: "hidden" }}>{value}</div>
+                            </div>);
+                        } else {
+                            let contentElement: (JSX.Element | null)[] | JSX.Element = [];
+                            contentElement = <EditableView key="editableView"
+                                contents={contents !== undefined ? Field.toString(contents as Field) : "null"}
+                                height={13}
+                                fontSize={10}
+                                GetValue={() => Field.toKeyValueString(doc, key)}
+                                SetValue={(value: string) => KeyValueBox.SetField(doc, key, value, true)}
+                            />;
+
+                            rows.push(<div style={{ display: "flex", overflowY: "visible", marginBottom: "-1px" }} key={key}>
+                                <span style={{ fontWeight: "bold", whiteSpace: "nowrap" }}>{key + ":"}</span>
+                            &nbsp;
+                            {contentElement}
+                            </div>);
+                        }
+                    }
+                }
+            }
+            rows.push(<div className="field" key={"newKeyValue"} style={{ marginTop: "3px" }}>
+                <EditableView
+                    key="editableView"
+                    contents={"add key:value or #tags"}
+                    height={13}
+                    fontSize={10}
+                    GetValue={() => ""}
+                    SetValue={this.setKeyValue} />
+            </div>);
+            return rows;
+        }
+    }
+
+
+    setKeyValue = (value: string) => {
+        if (this.selectedDoc && this.dataDoc) {
+            const doc = this.layoutFields ? Doc.Layout(this.selectedDoc) : this.dataDoc;
+            if (value.indexOf(":") !== -1) {
+                const newVal = value[0].toUpperCase() + value.substring(1, value.length);
+                KeyValueBox.SetField(doc, newVal.substring(0, newVal.indexOf(":")), newVal.substring(newVal.indexOf(":") + 1, newVal.length), true);
+                return true;
+            } else if (value[0] === "#") {
+                const newVal = value + `:'${value}'`;
+                KeyValueBox.SetField(doc, newVal.substring(0, newVal.indexOf(":")), newVal.substring(newVal.indexOf(":") + 1, newVal.length), true);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @computed get layoutPreview() {
+        if (this.selectedDoc) {
+            const layoutDoc = Doc.Layout(this.selectedDoc);
+            const panelHeight = StrCast(Doc.LayoutField(layoutDoc)).includes("FormattedTextBox") ? this.rtfHeight : this.docHeight;
+            const panelWidth = StrCast(Doc.LayoutField(layoutDoc)).includes("FormattedTextBox") ? this.rtfWidth : this.docWidth;
+            return <div style={{ display: "inline-block", height: panelHeight() }} key={this.selectedDoc[Id]}>
+                <ContentFittingDocumentView
+                    Document={layoutDoc}
+                    DataDoc={this.dataDoc}
+                    LibraryPath={emptyPath}
+                    renderDepth={this.props.renderDepth + 1}
+                    rootSelected={returnFalse}
+                    treeViewDoc={undefined}
+                    backgroundColor={() => "lightgrey"}
+                    fitToBox={false}
+                    FreezeDimensions={true}
+                    NativeWidth={layoutDoc.type ===
+                        StrCast(Doc.LayoutField(layoutDoc)).includes("FormattedTextBox") ? this.rtfWidth : returnZero}
+                    NativeHeight={layoutDoc.type ===
+                        StrCast(Doc.LayoutField(layoutDoc)).includes("FormattedTextBox") ? this.rtfHeight : returnZero}
+                    PanelWidth={panelWidth}
+                    PanelHeight={panelHeight}
+                    focus={returnFalse}
+                    ScreenToLocalTransform={this.props.ScreenToLocalTransform}
+                    docFilters={returnEmptyFilter}
+                    ContainingCollectionDoc={undefined}
+                    ContainingCollectionView={undefined}
+                    addDocument={returnFalse}
+                    moveDocument={undefined}
+                    removeDocument={returnFalse}
+                    parentActive={() => false}
+                    whenActiveChanged={emptyFunction}
+                    addDocTab={returnFalse}
+                    pinToPres={emptyFunction}
+                    bringToFront={returnFalse}
+                    ContentScaling={returnOne}
+                    dontRegisterView={true}
+                />
+            </div>;
+        } else {
+            return null;
+        }
+    }
+
+    getPermissionsSelect(user: string) {
+        return <select className="permissions-select"
+            onChange={e => SharingManager.Instance.shareFromPropertiesSidebar(user, e.currentTarget.value as SharingPermissions, this.selectedDoc!)}>
+            {Object.values(SharingPermissions).map(permission => {
+                return (
+                    <option key={permission} value={permission} selected={this.selectedDoc![`ACL-${user.replace(".", "_")}`] === permission}>
+                        {permission}
+                    </option>);
+            })}
+        </select>;
+    }
+
+    @computed get notifyIcon() {
+        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" />
+            </div>
+        </Tooltip>;
+    }
+
+    @computed get expansionIcon() {
+        return <Tooltip title={<><div className="dash-tooltip">{"Show more permissions"}</div></>}>
+            <div className="expansion-button" onPointerDown={() => {
+                if (this.selectedDocumentView) {
+                    SharingManager.Instance.open(this.selectedDocumentView);
+                }
+            }}>
+                <FontAwesomeIcon className="expansion-button-icon" icon="ellipsis-h" color="black" size="sm" />
+            </div>
+        </Tooltip>;
+    }
+
+    sharingItem(name: string, effectiveAcl: symbol, permission?: string) {
+        return <div className="propertiesView-sharingTable-item">
+            <div className="propertiesView-sharingTable-item-name" style={{ width: name !== "Me" ? "70px" : "80px" }}> {name} </div>
+            {name !== "Me" ? this.notifyIcon : null}
+            <div className="propertiesView-sharingTable-item-permission">
+                {effectiveAcl === AclAdmin && permission !== "Owner" ? this.getPermissionsSelect(name) : permission}
+                {permission === "Owner" ? this.expansionIcon : null}
+            </div>
+        </div>;
+    }
+
+    @computed get sharingTable() {
+        const AclMap = new Map<symbol, string>([
+            [AclPrivate, SharingPermissions.None],
+            [AclReadonly, SharingPermissions.View],
+            [AclAddonly, SharingPermissions.Add],
+            [AclEdit, SharingPermissions.Edit],
+            [AclAdmin, SharingPermissions.Admin]
+        ]);
+
+        const effectiveAcl = GetEffectiveAcl(this.selectedDoc!);
+        const tableEntries = [];
+
+        if (this.selectedDoc![AclSym]) {
+            for (const [key, value] of Object.entries(this.selectedDoc![AclSym])) {
+                const name = key.substring(4).replace("_", ".");
+                if (name !== Doc.CurrentUserEmail && name !== this.selectedDoc!.author) tableEntries.push(this.sharingItem(name, effectiveAcl, AclMap.get(value)!));
+            }
+        }
+
+        tableEntries.unshift(this.sharingItem("Me", effectiveAcl, Doc.CurrentUserEmail === this.selectedDoc!.author ? "Owner" : StrCast(this.selectedDoc![`ACL-${Doc.CurrentUserEmail.replace(".", "_")}`])));
+        if (Doc.CurrentUserEmail !== this.selectedDoc!.author) tableEntries.unshift(this.sharingItem(StrCast(this.selectedDoc!.author), effectiveAcl, "Owner"));
+
+        return <div className="propertiesView-sharingTable">
+            {tableEntries}
+        </div>;
+    }
+
+    @computed get fieldsCheckbox() {
+        return <Checkbox
+            color="primary"
+            onChange={this.toggleCheckbox}
+            checked={this.layoutFields}
+        />;
+    }
+
+    @action
+    toggleCheckbox = () => {
+        this.layoutFields = !this.layoutFields;
+    }
+
+    @computed get editableTitle() {
+        return <EditableView
+            key="editableView"
+            contents={StrCast(this.selectedDoc?.title)}
+            height={25}
+            fontSize={14}
+            GetValue={() => StrCast(this.selectedDoc?.title)}
+            SetValue={this.setTitle} />;
+    }
+
+    @action
+    setTitle = (value: string) => {
+        if (this.dataDoc) {
+            this.selectedDoc && (this.selectedDoc.title = value);
+            KeyValueBox.SetField(this.dataDoc, "title", value, true);
+            return true;
+        }
+        return false;
+    }
+
+
+
+
+
+
+
+
+
+    @undoBatch
+    @action
+    rotate = (angle: number) => {
+        const _centerPoints: { X: number, Y: number }[] = [];
+        if (this.selectedDoc) {
+            const doc = this.selectedDoc;
+            if (doc.type === DocumentType.INK && doc.x && doc.y && doc._width && doc._height && doc.data) {
+                const ink = Cast(doc.data, InkField)?.inkData;
+                if (ink) {
+                    const xs = ink.map(p => p.X);
+                    const ys = ink.map(p => p.Y);
+                    const left = Math.min(...xs);
+                    const top = Math.min(...ys);
+                    const right = Math.max(...xs);
+                    const bottom = Math.max(...ys);
+                    _centerPoints.push({ X: left, Y: top });
+                }
+            }
+
+            var index = 0;
+            if (doc.type === DocumentType.INK && doc.x && doc.y && doc._width && doc._height && doc.data) {
+                doc.rotation = Number(doc.rotation) + Number(angle);
+                const ink = Cast(doc.data, InkField)?.inkData;
+                if (ink) {
+
+                    const newPoints: { X: number, Y: number }[] = [];
+                    for (var i = 0; i < ink.length; i++) {
+                        const newX = Math.cos(angle) * (ink[i].X - _centerPoints[index].X) - Math.sin(angle) * (ink[i].Y - _centerPoints[index].Y) + _centerPoints[index].X;
+                        const newY = Math.sin(angle) * (ink[i].X - _centerPoints[index].X) + Math.cos(angle) * (ink[i].Y - _centerPoints[index].Y) + _centerPoints[index].Y;
+                        newPoints.push({ X: newX, Y: newY });
+                    }
+                    doc.data = new InkField(newPoints);
+                    const xs = newPoints.map(p => p.X);
+                    const ys = newPoints.map(p => p.Y);
+                    const left = Math.min(...xs);
+                    const top = Math.min(...ys);
+                    const right = Math.max(...xs);
+                    const bottom = Math.max(...ys);
+
+                    doc._height = (bottom - top);
+                    doc._width = (right - left);
+                }
+                index++;
+            }
+        }
+    }
+
+    @observable _controlBtn: boolean = false;
+    @observable _lock: boolean = false;
+
+    @computed
+    get controlPointsButton() {
+        return <div className="inking-button">
+            <Tooltip title={<><div className="dash-tooltip">{"Edit points"}</div></>}>
+                <div className="inking-button-points" onPointerDown={action(() => this._controlBtn = !this._controlBtn)} style={{ backgroundColor: this._controlBtn ? "black" : "" }}>
+                    <FontAwesomeIcon icon="bezier-curve" color="white" size="lg" />
+                </div>
+            </Tooltip>
+            <Tooltip title={<><div className="dash-tooltip">{this._lock ? "Unlock points" : "Lock points"}</div></>}>
+                <div className="inking-button-lock" onPointerDown={action(() => this._lock = !this._lock)} >
+                    <FontAwesomeIcon icon={this._lock ? "unlock" : "lock"} color="white" size="lg" />
+                </div>
+            </Tooltip>
+            <Tooltip title={<><div className="dash-tooltip">{"Rotate 90˚"}</div></>}>
+                <div className="inking-button-rotate" onPointerDown={action(() => this.rotate(Math.PI / 2))}>
+                    <FontAwesomeIcon icon="undo" color="white" size="lg" />
+                </div>
+            </Tooltip>
+        </div>;
+    }
+
+    inputBox = (key: string, value: any, setter: (val: string) => {}, title: string) => {
+        return <div className="inputBox"
+            style={{
+                marginRight: title === "X:" ? "19px" : "",
+                marginLeft: title === "∠:" ? "39px" : ""
+            }}>
+            <div className="inputBox-title"> {title} </div>
+            <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" />
+                </div>
+                <div className="inputbox-Button-down" key="down2"
+                    onPointerDown={undoBatch(action(() => this.upDownButtons("down", key)))} >
+                    <FontAwesomeIcon icon="caret-down" color="white" size="sm" />
+                </div>
+            </div>
+        </div>;
+    }
+
+    inputBoxDuo = (key: string, value: any, setter: (val: string) => {}, title1: string, key2: string, value2: any, setter2: (val: string) => {}, title2: string) => {
+        return <div className="inputBox-duo">
+            {this.inputBox(key, value, setter, title1)}
+            {title2 === "" ? (null) : this.inputBox(key2, value2, setter2, title2)}
+        </div>;
+    }
+
+    @action
+    upDownButtons = (dirs: string, field: string) => {
+        switch (field) {
+            case "rot": this.rotate((dirs === "up" ? .1 : -.1)); break;
+            // case "rot": this.selectedInk?.forEach(i => i.rootDoc.rotation = NumCast(i.rootDoc.rotation) + (dirs === "up" ? 0.1 : -0.1)); break;
+            case "Xps": this.selectedDoc && (this.selectedDoc.x = NumCast(this.selectedDoc?.x) + (dirs === "up" ? 10 : -10)); break;
+            case "Yps": this.selectedDoc && (this.selectedDoc.y = NumCast(this.selectedDoc?.y) + (dirs === "up" ? 10 : -10)); break;
+            case "stk": this.selectedDoc && (this.selectedDoc.strokeWidth = NumCast(this.selectedDoc?.strokeWidth) + (dirs === "up" ? .1 : -.1)); break;
+            case "wid":
+                const oldWidth = NumCast(this.selectedDoc?._width);
+                const oldHeight = NumCast(this.selectedDoc?._height);
+                const oldX = NumCast(this.selectedDoc?.x);
+                const oldY = NumCast(this.selectedDoc?.y);
+                this.selectedDoc && (this.selectedDoc._width = oldWidth + (dirs === "up" ? 10 : - 10));
+                this._lock && this.selectedDoc && (this.selectedDoc._height = (NumCast(this.selectedDoc?._width) / oldWidth * NumCast(this.selectedDoc?._height)));
+                const doc = this.selectedDoc;
+                if (doc?.type === DocumentType.INK && doc.x && doc.y && doc._height && doc._width) {
+                    console.log(doc.x, doc.y, doc._height, doc._width);
+                    const ink = Cast(doc.data, InkField)?.inkData;
+                    console.log(ink);
+                    if (ink) {
+                        const newPoints: { X: number, Y: number }[] = [];
+                        for (var j = 0; j < ink.length; j++) {
+                            // (new x — oldx) + (oldxpoint * newWidt)/oldWidth 
+                            const newX = (NumCast(doc.x) - oldX) + (ink[j].X * NumCast(doc._width)) / oldWidth;
+                            const newY = (NumCast(doc.y) - oldY) + (ink[j].Y * NumCast(doc._height)) / oldHeight;
+                            newPoints.push({ X: newX, Y: newY });
+                        }
+                        doc.data = new InkField(newPoints);
+                    }
+                }
+                break;
+            case "hgt":
+                const oWidth = NumCast(this.selectedDoc?._width);
+                const oHeight = NumCast(this.selectedDoc?._height);
+                const oX = NumCast(this.selectedDoc?.x);
+                const oY = NumCast(this.selectedDoc?.y);
+                this.selectedDoc && (this.selectedDoc._height = oHeight + (dirs === "up" ? 10 : - 10));
+                this._lock && this.selectedDoc && (this.selectedDoc._width = (NumCast(this.selectedDoc?._height) / oHeight * NumCast(this.selectedDoc?._width)));
+                const docu = this.selectedDoc;
+                if (docu?.type === DocumentType.INK && docu.x && docu.y && docu._height && docu._width) {
+                    console.log(docu.x, docu.y, docu._height, docu._width);
+                    const ink = Cast(docu.data, InkField)?.inkData;
+                    console.log(ink);
+                    if (ink) {
+                        const newPoints: { X: number, Y: number }[] = [];
+                        for (var j = 0; j < ink.length; j++) {
+                            // (new x — oldx) + (oldxpoint * newWidt)/oldWidth 
+                            const newX = (NumCast(docu.x) - oX) + (ink[j].X * NumCast(docu._width)) / oWidth;
+                            const newY = (NumCast(docu.y) - oY) + (ink[j].Y * NumCast(docu._height)) / oHeight;
+                            newPoints.push({ X: newX, Y: newY });
+                        }
+                        docu.data = new InkField(newPoints);
+                    }
+                }
+                break;
+        }
+    }
+
+    getField(key: string) {
+        //if (this.selectedDoc) {
+        return Field.toString(this.selectedDoc[key] as Field);
+        // } else {
+        //     return undefined as Opt<string>;
+        // }
+    }
+
+    @computed get shapeXps() { return this.getField("x"); }
+    @computed get shapeYps() { return this.getField("y"); }
+    @computed get shapeRot() { return this.getField("rotation"); }
+    @computed get shapeHgt() { return this.getField("_height"); }
+    @computed get shapeWid() { return this.getField("_width"); }
+    set shapeXps(value) { this.selectedDoc && (this.selectedDoc.x = Number(value)); }
+    set shapeYps(value) { this.selectedDoc && (this.selectedDoc.y = Number(value)); }
+    set shapeRot(value) { this.selectedDoc && (this.selectedDoc.rotation = Number(value)); }
+    set shapeWid(value) {
+        const oldWidth = NumCast(this.selectedDoc?._width);
+        this.selectedDoc && (this.selectedDoc._width = Number(value));
+        this._lock && this.selectedDoc && (this.selectedDoc._height = (NumCast(this.selectedDoc?._width) * NumCast(this.selectedDoc?._height)) / oldWidth);
+    }
+    set shapeHgt(value) {
+        const oldHeight = NumCast(this.selectedDoc?._height);
+        this.selectedDoc && (this.selectedDoc._height = Number(value));
+        this._lock && this.selectedDoc && (this.selectedDoc._width = (NumCast(this.selectedDoc?._height) * NumCast(this.selectedDoc?._width)) / oldHeight);
+    }
+
+    @computed get hgtInput() { return this.inputBoxDuo("hgt", this.shapeHgt, (val: string) => this.shapeHgt = val, "H:", "wid", this.shapeWid, (val: string) => this.shapeWid = val, "W:"); }
+    @computed get XpsInput() { return this.inputBoxDuo("Xps", this.shapeXps, (val: string) => this.shapeXps = val, "X:", "Yps", this.shapeYps, (val: string) => this.shapeYps = val, "Y:"); }
+    @computed get rotInput() { return this.inputBoxDuo("rot", this.shapeRot, (val: string) => { this.rotate(Number(val) - Number(this.shapeRot)); this.shapeRot = val; return true; }, "∠:", "rot", this.shapeRot, (val: string) => this.shapeRot = val, ""); }
+
+    @observable private _fillBtn = false;
+    @observable private _lineBtn = false;
+
+    private _lastFill = "#D0021B";
+    private _lastLine = "#D0021B";
+    private _lastDash: any = "2";
+
+    @computed get colorFil() { const ccol = this.getField("fillColor") || ""; ccol && (this._lastFill = ccol); return ccol; }
+    @computed get colorStk() { const ccol = this.getField("color") || ""; ccol && (this._lastLine = ccol); return ccol; }
+    set colorFil(value) { value && (this._lastFill = value); this.selectedDoc && (this.selectedDoc.fillColor = value ? value : undefined); }
+    set colorStk(value) { value && (this._lastLine = value); this.selectedDoc && (this.selectedDoc.color = value ? value : undefined); }
+
+    colorButton(value: string, setter: () => {}) {
+        return <div className="color-button" key="color" onPointerDown={undoBatch(action(e => setter()))}>
+            <div className="color-button-preview" style={{
+                backgroundColor: value ?? "121212", width: 15, height: 15,
+                display: value === "" || value === "transparent" ? "none" : ""
+            }} />
+            {value === "" || value === "transparent" ? <p style={{ fontSize: 25, color: "red", marginTop: -14, position: "fixed" }}>☒</p> : ""}
+        </div>;
+    }
+
+    @undoBatch
+    @action
+    switchStk = (color: ColorState) => {
+        const val = String(color.hex);
+        this.colorStk = val;
+        return true;
+    }
+    @undoBatch
+    @action
+    switchFil = (color: ColorState) => {
+        const val = String(color.hex);
+        this.colorFil = val;
+        return true;
+    }
+
+    colorPicker(setter: (color: string) => {}, type: string) {
+        return <SketchPicker onChange={type === "stk" ? this.switchStk : this.switchFil}
+            presetColors={['#D0021B', '#F5A623', '#F8E71C', '#8B572A', '#7ED321', '#417505',
+                '#9013FE', '#4A90E2', '#50E3C2', '#B8E986', '#000000', '#4A4A4A', '#9B9B9B',
+                '#FFFFFF', '#f1efeb', 'transparent']}
+            color={type === "stk" ? this.colorStk : this.colorFil} />;
+    }
+
+    @computed get fillButton() { return this.colorButton(this.colorFil, () => { this._fillBtn = !this._fillBtn; this._lineBtn = false; return true; }); }
+    @computed get lineButton() { return this.colorButton(this.colorStk, () => { this._lineBtn = !this._lineBtn; this._fillBtn = false; return true; }); }
+
+    @computed get fillPicker() { return this.colorPicker((color: string) => this.colorFil = color, "fil"); }
+    @computed get linePicker() { return this.colorPicker((color: string) => this.colorStk = color, "stk"); }
+
+    @computed get strokeAndFill() {
+        return <div>
+            <div key="fill" className="strokeAndFill">
+                <div className="fill">
+                    <div className="fill-title">Fill:</div>
+                    <div className="fill-button">{this.fillButton}</div>
+                </div>
+                <div className="stroke">
+                    <div className="stroke-title"> Stroke: </div>
+                    <div className="stroke-button">{this.lineButton}</div>
+                </div>
+            </div>
+            {this._fillBtn ? this.fillPicker : ""}
+            {this._lineBtn ? this.linePicker : ""}
+        </div>;
+    }
+
+    @computed get solidStk() { return this.selectedDoc?.color && (!this.selectedDoc?.strokeDash || this.selectedDoc?.strokeDash === "0") ? true : false; }
+    @computed get dashdStk() { return this.selectedDoc?.strokeDash || ""; }
+    @computed get unStrokd() { return this.selectedDoc?.color ? true : false; }
+    @computed get widthStk() { return this.getField("strokeWidth") || "1"; }
+    @computed get markHead() { return this.getField("strokeStartMarker") || ""; }
+    @computed get markTail() { return this.getField("strokeEndMarker") || ""; }
+    set solidStk(value) { this.dashdStk = ""; this.unStrokd = !value; }
+    set dashdStk(value) {
+        value && (this._lastDash = value) && (this.unStrokd = false);
+        this.selectedDoc && (this.selectedDoc.strokeDash = value ? this._lastDash : undefined);
+    }
+    set widthStk(value) { this.selectedDoc && (this.selectedDoc.strokeWidth = Number(value)); }
+    set unStrokd(value) { this.colorStk = value ? "" : this._lastLine; }
+    set markHead(value) { this.selectedDoc && (this.selectedDoc.strokeStartMarker = value); }
+    set markTail(value) { this.selectedDoc && (this.selectedDoc.strokeEndMarker = value); }
+
+
+    @computed get stkInput() { return this.regInput("stk", this.widthStk, (val: string) => this.widthStk = val); }
+
+
+    regInput = (key: string, value: any, setter: (val: string) => {}) => {
+        return <div className="inputBox">
+            <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" />
+                </div>
+                <div className="inputbox-Button-down" key="down2"
+                    onPointerDown={undoBatch(action(() => this.upDownButtons("down", key)))} >
+                    <FontAwesomeIcon icon="caret-down" color="white" size="sm" />
+                </div>
+            </div>
+        </div>;
+    }
+
+    @computed get widthAndDash() {
+        return <div className="widthAndDash">
+            <div className="width">
+                <div className="width-top">
+                    <div className="width-title">Width:</div>
+                    <div className="width-input">{this.stkInput}</div>
+                </div>
+                <input className="width-range" type="range"
+                    defaultValue={Number(this.widthStk)} min={1} max={100}
+                    onChange={undoBatch(action((e) => this.widthStk = e.target.value))} />
+            </div>
+
+            <div className="arrows">
+                <div className="arrows-head">
+                    <div className="arrows-head-title" >Arrow Head: </div>
+                    <input key="markHead" className="arrows-head-input" type="checkbox"
+                        checked={this.markHead !== ""}
+                        onChange={undoBatch(action(() => this.markHead = this.markHead ? "" : "arrow"))} />
+                </div>
+                <div className="arrows-tail">
+                    <div className="arrows-tail-title" >Arrow End: </div>
+                    <input key="markTail" className="arrows-tail-input" type="checkbox"
+                        checked={this.markTail !== ""}
+                        onChange={undoBatch(action(() => this.markTail = this.markTail ? "" : "arrow"))} />
+                </div>
+            </div>
+            <div className="dashed">
+                <div className="dashed-title">Dash:</div>
+                <input key="markHead" className="dashed-input"
+                    type="checkbox" checked={this.dashdStk === "2"}
+                    onChange={this.changeDash} />
+            </div>
+        </div>;
+    }
+
+    @undoBatch @action
+    changeDash = () => {
+        const dash = this.dashdStk;
+        if (dash === "2") {
+            this.dashdStk = "0";
+        } else {
+            this.dashdStk = "2";
+        }
+    }
+
+    @computed get appearanceEditor() {
+        return <div className="appearance-editor">
+            {this.widthAndDash}
+            {this.strokeAndFill}
+        </div>;
+    }
+
+    @computed get transformEditor() {
+        return <div className="transform-editor">
+            {this.controlPointsButton}
+            {this.hgtInput}
+            {this.XpsInput}
+            {this.rotInput}
+        </div>;
+    }
+
+    render() {
+
+        if (!this.selectedDoc) {
+            return <div className="propertiesView" style={{ width: this.props.width }}>
+                <div className="propertiesView-title" style={{ width: this.props.width, paddingLeft: 6 }}>
+                    No Document Selected
+            </div> </div>;
+        }
+
+        const novice = Doc.UserDoc().noviceMode;
+
+        return <div className="propertiesView" style={{ width: this.props.width }} >
+            <div className="propertiesView-title" style={{ width: this.props.width }}>
+                Properties
+                <div className="propertiesView-title-icon" onPointerDown={this.props.onDown}>
+                    <FontAwesomeIcon icon="times" color="black" size="sm" />
+                </div>
+            </div>
+            <div className="propertiesView-name">
+                {this.editableTitle}
+            </div>
+            <div className="propertiesView-settings">
+                <div className="propertiesView-settings-title"
+                    onPointerDown={() => runInAction(() => { this.openActions = !this.openActions; })}
+                    style={{ backgroundColor: this.openActions ? "black" : "" }}>
+                    Actions
+                    <div className="propertiesView-settings-title-icon">
+                        <FontAwesomeIcon icon={this.openActions ? "caret-down" : "caret-right"} size="lg" color="white" />
+                    </div>
+                </div>
+                {this.openActions ? <div className="propertiesView-settings-content">
+                    <PropertiesButtons />
+                </div> : null}
+            </div>
+            <div className="propertiesView-sharing">
+                <div className="propertiesView-sharing-title"
+                    onPointerDown={() => runInAction(() => { 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 ? <div className="propertiesView-sharing-content">
+                    {this.sharingTable}
+                </div> : null}
+            </div>
+
+
+
+
+            {this.isInk ? <div className="propertiesView-appearance">
+                <div className="propertiesView-appearance-title"
+                    onPointerDown={() => runInAction(() => { 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 ? <div className="propertiesView-appearance-content">
+                    {this.appearanceEditor}
+                </div> : null}
+            </div> : null}
+
+            {this.isInk ? <div className="propertiesView-transform">
+                <div className="propertiesView-transform-title"
+                    onPointerDown={() => runInAction(() => { 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> : null}
+
+
+
+
+
+            <div className="propertiesView-fields">
+                <div className="propertiesView-fields-title"
+                    onPointerDown={() => runInAction(() => { this.openFields = !this.openFields; })}
+                    style={{ backgroundColor: this.openFields ? "black" : "" }}>
+                    <div className="propertiesView-fields-title-name">
+                        Fields {"&"} Tags
+                        <div className="propertiesView-fields-title-icon">
+                            <FontAwesomeIcon icon={this.openFields ? "caret-down" : "caret-right"} size="lg" color="white" />
+                        </div>
+                    </div>
+                </div>
+                {!novice && this.openFields ? <div className="propertiesView-fields-checkbox">
+                    {this.fieldsCheckbox}
+                    <div className="propertiesView-fields-checkbox-text">Layout</div>
+                </div> : null}
+                {this.openFields ?
+                    <div className="propertiesView-fields-content">
+                        {novice ? this.noviceFields : this.expandedField}
+                    </div> : null}
+            </div>
+            <div className="propertiesView-layout">
+                <div className="propertiesView-layout-title"
+                    onPointerDown={() => runInAction(() => { this.openLayout = !this.openLayout; })}
+                    style={{ backgroundColor: this.openLayout ? "black" : "" }}>
+                    Layout
+                    <div className="propertiesView-layout-title-icon"
+                        onPointerDown={() => runInAction(() => { this.openLayout = !this.openLayout; })}>
+                        <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>
+        </div>;
+    }
+} 
\ No newline at end of file
diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx
index d1c839c3b..0aabf5319 100644
--- a/src/client/views/linking/LinkMenuItem.tsx
+++ b/src/client/views/linking/LinkMenuItem.tsx
@@ -182,7 +182,7 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
         switch (this.props.destinationDoc.type) {
             case DocumentType.IMG: destinationIcon = "image"; break;
             case DocumentType.COMPARISON: destinationIcon = "columns"; break;
-            case DocumentType.RTF: destinationIcon = "font"; break;
+            case DocumentType.RTF: destinationIcon = "sticky-note"; break;
             case DocumentType.COL: destinationIcon = "folder"; break;
             case DocumentType.WEB: destinationIcon = "globe-asia"; break;
             case DocumentType.SCREENSHOT: destinationIcon = "photo-video"; break;
@@ -196,6 +196,7 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
             case DocumentType.DOCHOLDER: destinationIcon = "expand"; break;
             case DocumentType.VID: destinationIcon = "video"; break;
             case DocumentType.INK: destinationIcon = "pen-nib"; break;
+            case DocumentType.PDF: destinationIcon = "file"; break;
             default: destinationIcon = "question"; break;
         }
 
diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx
index 6081def5d..f7e253f42 100644
--- a/src/client/views/nodes/ContentFittingDocumentView.tsx
+++ b/src/client/views/nodes/ContentFittingDocumentView.tsx
@@ -78,6 +78,9 @@ export class ContentFittingDocumentView extends React.Component<DocumentViewProp
 
     render() {
         TraceMobx();
+        if (this.props.Document.title === "Archive") {
+            console.log("");
+        }
         return (<div className="contentFittingDocumentView" style={{
             width: Math.abs(this.centeringYOffset) > 0.001 ? "auto" : this.props.PanelWidth(),
             height: Math.abs(this.centeringOffset) > 0.0001 ? "auto" : this.props.PanelHeight(),
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index e8173d103..e3f258b8d 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -18,6 +18,7 @@ import { DocHolderBox } from "./DocHolderBox";
 import { DocumentViewProps } from "./DocumentView";
 import "./DocumentView.scss";
 import { FontIconBox } from "./FontIconBox";
+import { MenuIconBox } from "./MenuIconBox";
 import { FieldView, FieldViewProps } from "./FieldView";
 import { FormattedTextBox } from "./formattedText/FormattedTextBox";
 import { ImageBox } from "./ImageBox";
@@ -189,7 +190,7 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
                 blacklistedAttrs={[]}
                 renderInWrapper={false}
                 components={{
-                    FormattedTextBox, ImageBox, DirectoryImportBox, FontIconBox, LabelBox, SliderBox, FieldView,
+                    FormattedTextBox, ImageBox, DirectoryImportBox, FontIconBox, MenuIconBox, LabelBox, SliderBox, FieldView,
                     CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, WebBox, KeyValueBox,
                     PDFBox, VideoBox, AudioBox, PresBox, YoutubeBox, PresElementBox, QueryBox,
                     ColorBox, DashWebRTCVideo, LinkAnchorBox, InkingStroke, DocHolderBox, LinkBox, ScriptingBox,
diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx
index 3b91ac6b5..198a90225 100644
--- a/src/client/views/nodes/DocumentLinksButton.tsx
+++ b/src/client/views/nodes/DocumentLinksButton.tsx
@@ -198,8 +198,11 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
             // }))} 
             >
 
+                {/* {this.props.InMenu ? this.props.StartLink ? <FontAwesomeIcon className="documentdecorations-icon" icon="link" size="sm" /> :
+                    <FontAwesomeIcon className="documentdecorations-icon" icon="hand-paper" size="sm" /> : links.length} */}
+
                 {this.props.InMenu ? this.props.StartLink ? <FontAwesomeIcon className="documentdecorations-icon" icon="link" size="sm" /> :
-                    <FontAwesomeIcon className="documentdecorations-icon" icon="hand-paper" size="sm" /> : links.length}
+                    link : links.length}
 
             </div>
             {DocumentLinksButton.StartLink && this.props.InMenu && !!!this.props.StartLink && DocumentLinksButton.StartLink !== this.props.View ? <div className={"documentLinksButton-endLink"}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index b3bfadf4f..22a2bb8fe 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -94,6 +94,8 @@ export interface DocumentViewProps {
     layoutKey?: string;
     radialMenu?: String[];
     display?: string;
+    relative?: boolean;
+    scriptContext?: any;
 }
 
 @observer
@@ -287,7 +289,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     }
 
     onClick = action((e: React.MouseEvent | React.PointerEvent) => {
-        if (!e.nativeEvent.cancelBubble && !this.Document.ignoreClick &&
+        if (!e.nativeEvent.cancelBubble && !this.Document.ignoreClick && this.props.renderDepth >= 0 &&
             (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD)) {
             let stopPropagate = true;
             let preventDefault = true;
@@ -319,10 +321,11 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 const func = () => this.onClickHandler.script.run({
                     this: this.layoutDoc,
                     self: this.rootDoc,
+                    scriptContext: this.props.scriptContext,
                     thisContainer: this.props.ContainingCollectionDoc,
                     shiftKey: e.shiftKey
                 }, console.log);
-                if (this.props.Document !== Doc.UserDoc()["dockedBtn-undo"] && this.props.Document !== Doc.UserDoc()["dockedBtn-redo"]) {
+                if (!Doc.AreProtosEqual(this.props.Document, Doc.UserDoc()["dockedBtn-undo"] as Doc) && !Doc.AreProtosEqual(this.props.Document, Doc.UserDoc()["dockedBtn-redo"] as Doc)) {
                     UndoManager.RunInBatch(func, "on click");
                 } else func();
             } else if (this.Document["onClick-rawScript"] && !StrCast(Doc.LayoutField(this.layoutDoc))?.includes("ScriptingBox")) {// bcz: hack? don't edit a script if you're clicking on a scripting box itself
@@ -584,6 +587,18 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         }
     }
 
+
+    @undoBatch
+    noOnClick = (): void => {
+        this.Document.ignoreClick = false;
+        this.Document.isLinkButton = false;
+    }
+
+    @undoBatch
+    toggleDetail = (): void => {
+        this.Document.onClick = ScriptField.MakeScript(`toggleDetail(self, "${this.Document.layoutKey}")`);
+    }
+
     @undoBatch @action
     drop = async (e: Event, de: DragManager.DropEvent) => {
         if (this.props.Document === Doc.UserDoc().activeWorkspace) {
@@ -660,6 +675,14 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         }
     }
 
+    @action
+    onCopy = () => {
+        const copy = Doc.MakeCopy(this.props.Document, true);
+        copy.x = NumCast(this.props.Document.x) + NumCast(this.props.Document._width);
+        copy.y = NumCast(this.props.Document.y) + 30;
+        this.props.addDocument?.(copy);
+    }
+
     @action
     onContextMenu = async (e: React.MouseEvent | Touch): Promise<void> => {
         // the touch onContextMenu is button 0, the pointer onContextMenu is button 2
@@ -704,14 +727,14 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         const existingOnClick = cm.findByDescription("OnClick...");
         const onClicks: ContextMenuProps[] = existingOnClick && "subitems" in existingOnClick ? existingOnClick.subitems : [];
         onClicks.push({ description: "Enter Portal", event: this.makeIntoPortal, icon: "window-restore" });
-        onClicks.push({ description: "Toggle Detail", event: () => this.Document.onClick = ScriptField.MakeScript(`toggleDetail(self, "${this.Document.layoutKey}")`), icon: "window-restore" });
+        onClicks.push({ description: "Toggle Detail", event: () => this.Document.onClick = ScriptField.MakeScript(`toggleDetail(self, "${this.Document.layoutKey}")`), icon: "concierge-bell" });
         onClicks.push({ description: this.Document.ignoreClick ? "Select" : "Do Nothing", event: () => this.Document.ignoreClick = !this.Document.ignoreClick, icon: this.Document.ignoreClick ? "unlock" : "lock" });
-        onClicks.push({ description: this.Document.isLinkButton ? "Remove Follow Behavior" : "Follow Link in Place", event: () => this.toggleFollowLink("inPlace", true, false), icon: "concierge-bell" });
-        !this.Document.isLinkButton && onClicks.push({ description: "Follow Link on Right", event: () => this.toggleFollowLink("onRight", false, false), icon: "concierge-bell" });
-        onClicks.push({ description: this.Document.isLinkButton || this.onClickHandler ? "Remove Click Behavior" : "Follow Link", event: () => this.toggleFollowLink(undefined, false, false), icon: "concierge-bell" });
-        onClicks.push({ description: (this.Document.isPushpin ? "Remove" : "Make") + " Pushpin", event: () => this.toggleFollowLink(undefined, false, true), icon: "snowflake" });
-        onClicks.push({ description: "Edit onClick Script", event: () => UndoManager.RunInBatch(() => DocUtils.makeCustomViewClicked(this.props.Document, undefined, "onClick"), "edit onClick"), icon: "edit" });
-        !existingOnClick && cm.addItem({ description: "OnClick...", noexpand: true, addDivider: true, subitems: onClicks, icon: "hand-point-right" });
+        onClicks.push({ description: this.Document.isLinkButton ? "Remove Follow Behavior" : "Follow Link in Place", event: () => this.toggleFollowLink("inPlace", true, false), icon: "link" });
+        !this.Document.isLinkButton && onClicks.push({ description: "Follow Link on Right", event: () => this.toggleFollowLink("onRight", false, false), icon: "link" });
+        onClicks.push({ description: this.Document.isLinkButton || this.onClickHandler ? "Remove Click Behavior" : "Follow Link", event: () => this.toggleFollowLink(undefined, false, false), icon: "link" });
+        onClicks.push({ description: (this.Document.isPushpin ? "Remove" : "Make") + " Pushpin", event: () => this.toggleFollowLink(undefined, false, true), icon: "map-pin" });
+        onClicks.push({ description: "Edit onClick Script", event: () => UndoManager.RunInBatch(() => DocUtils.makeCustomViewClicked(this.props.Document, undefined, "onClick"), "edit onClick"), icon: "terminal" });
+        !existingOnClick && cm.addItem({ description: "OnClick...", noexpand: true, addDivider: true, subitems: onClicks, icon: "mouse-pointer" });
 
         const funcs: ContextMenuProps[] = [];
         if (this.layoutDoc.onDragStart) {
@@ -724,6 +747,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         const more = cm.findByDescription("More...");
         const moreItems = more && "subitems" in more ? more.subitems : [];
         moreItems.push({ description: "Download document", icon: "download", event: async () => Doc.Zip(this.props.Document) });
+        moreItems.push({ description: "Share", event: () => SharingManager.Instance.open(this), icon: "users" });
+        //moreItems.push({ description: this.Document.lockedPosition ? "Unlock Position" : "Lock Position", event: this.toggleLockPosition, icon: BoolCast(this.Document.lockedPosition) ? "unlock" : "lock" });
+        moreItems.push({ description: "Create an Alias", event: () => this.onCopy(), icon: "copy" });
         if (!Doc.UserDoc().noviceMode) {
             moreItems.push({ description: "Make View of Metadata Field", event: () => Doc.MakeMetadataFieldTemplate(this.props.Document, this.props.DataDoc), icon: "concierge-bell" });
             moreItems.push({ description: `${this.Document._chromeStatus !== "disabled" ? "Hide" : "Show"} Chrome`, event: () => this.Document._chromeStatus = (this.Document._chromeStatus !== "disabled" ? "disabled" : "enabled"), icon: "project-diagram" });
@@ -735,16 +761,18 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             }
             moreItems.push({ description: "Copy ID", event: () => Utils.CopyText(Utils.prepend("/doc/" + this.props.Document[Id])), icon: "fingerprint" });
         }
+        //GetEffectiveAcl(this.props.Document) === AclEdit && moreItems.push({ description: "Delete", event: this.deleteClicked, icon: "trash" });
+
         const effectiveAcl = GetEffectiveAcl(this.props.Document);
         (effectiveAcl === AclEdit || effectiveAcl === AclAdmin) && moreItems.push({ description: "Delete", event: this.deleteClicked, icon: "trash" });
-        moreItems.push({ description: "Share", event: () => SharingManager.Instance.open(this), icon: "external-link-alt" });
+
         !more && cm.addItem({ description: "More...", subitems: moreItems, icon: "hand-point-right" });
         cm.moveAfter(cm.findByDescription("More...")!, cm.findByDescription("OnClick...")!);
 
         const help = cm.findByDescription("Help...");
         const helpItems: ContextMenuProps[] = help && "subitems" in help ? help.subitems : [];
+        !Doc.UserDoc().novice && helpItems.push({ description: "Show Fields ", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), "onRight"), icon: "layer-group" });
         helpItems.push({ description: "Text Shortcuts Ctrl+/", event: () => this.props.addDocTab(Docs.Create.PdfDocument(Utils.prepend("/assets/cheat-sheet.pdf"), { _width: 300, _height: 300 }), "onRight"), icon: "keyboard" });
-        helpItems.push({ description: "Show Fields ", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), "onRight"), icon: "layer-group" });
         helpItems.push({ description: "Print Document in Console", event: () => console.log(this.props.Document), icon: "hand-point-right" });
         cm.addItem({ description: "Help...", noexpand: true, subitems: helpItems, icon: "question" });
 
@@ -786,8 +814,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     childScaling = () => (this.layoutDoc._fitWidth ? this.props.PanelWidth() / this.nativeWidth : this.props.ContentScaling());
     @computed.struct get linkOffset() { return [-15, 0]; }
     @computed get contents() {
+        const pos = this.props.relative ? "relative " : "absolute";
         TraceMobx();
-        return (<div style={{ position: "absolute", width: "100%", height: "100%" }}>
+        return (<div style={{ width: "100%", height: "100%" }}>
             <DocumentContentsView key={1}
                 docFilters={this.props.docFilters}
                 ContainingCollectionView={this.props.ContainingCollectionView}
@@ -823,6 +852,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 ChromeHeight={this.chromeHeight}
                 isSelected={this.isSelected}
                 select={this.select}
+                scriptContext={this.props.scriptContext}
                 onClick={this.onClickFunc}
                 layoutKey={this.finalLayoutKey} />
             {this.layoutDoc.hideAllLinks ? (null) : this.allAnchors}
@@ -877,8 +907,12 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     }
     @computed get innards() {
         TraceMobx();
+        const pos = this.props.relative ? "relative" : undefined;
         if (this.props.treeViewDoc && !this.props.LayoutTemplateString?.includes("LinkAnchorBox")) {  // this happens when the document is a tree view label (but not an anchor dot)
-            return <div className="documentView-treeView" style={{ maxWidth: this.props.PanelWidth() || undefined }}>
+            return <div className="documentView-treeView" style={{
+                maxWidth: this.props.PanelWidth() || undefined,
+                position: pos
+            }}>
                 {StrCast(this.props.Document.title)}
                 {this.allAnchors}
             </div>;
@@ -1003,7 +1037,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 background: finalColor,
                 opacity: finalOpacity,
                 fontFamily: StrCast(this.Document._fontFamily, "inherit"),
-                fontSize: Cast(this.Document._fontSize, "string", null)
+                fontSize: Cast(this.Document._fontSize, "string", null),
             }}>
             {this.onClickHandler && this.props.ContainingCollectionView?.props.Document._viewType === CollectionViewType.Time ? <>
                 {this.innards}
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 5d5bc1d73..1b4151bd8 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -61,6 +61,7 @@ export interface FieldViewProps {
     color?: string;
     xMargin?: number;
     yMargin?: number;
+    scriptContext?: any;
 }
 
 @observer
diff --git a/src/client/views/nodes/FontIconBox.scss b/src/client/views/nodes/FontIconBox.scss
index 5b85d8b0b..69c835318 100644
--- a/src/client/views/nodes/FontIconBox.scss
+++ b/src/client/views/nodes/FontIconBox.scss
@@ -16,7 +16,7 @@
         position: absolute;
         text-align: center;
         font-size: 8px;
-        margin-top:4px;
+        //margin-top:4px;
         letter-spacing: normal;
         left: 0;
         overflow: hidden;
diff --git a/src/client/views/nodes/MenuIconBox.scss b/src/client/views/nodes/MenuIconBox.scss
new file mode 100644
index 000000000..1b72f5a8f
--- /dev/null
+++ b/src/client/views/nodes/MenuIconBox.scss
@@ -0,0 +1,49 @@
+.menuButton {
+    //padding: 7px;
+    padding-left: 7px;
+    width: 100%;
+    width: 60px;
+    height: 70px;
+
+    .menuButton-wrap {
+        width: 45px;
+        /* padding: 5px; */
+        touch-action: none;
+        background: black;
+        transform-origin: top left;
+        /* margin-bottom: 5px; */
+        margin-top: 5px;
+        margin-right: 25px;
+        border-radius: 8px;
+
+        &:hover {
+            background: rgb(61, 61, 61);
+            cursor: pointer;
+        }
+    }
+
+    .menuButton-label {
+        color: white;
+        margin-right: 4px;
+        border-radius: 8px;
+        width: 42px;
+        position: relative;
+        text-align: center;
+        font-size: 8px;
+        margin-top: 1px;
+        letter-spacing: normal;
+        padding: 3px;
+        background-color: inherit;
+    }
+
+    .menuButton-icon {
+        width: auto;
+        height: 35px;
+        padding: 5px;
+    }
+
+    svg {
+        width: 95% !important;
+        height: 95%;
+    }
+}
\ No newline at end of file
diff --git a/src/client/views/nodes/MenuIconBox.tsx b/src/client/views/nodes/MenuIconBox.tsx
new file mode 100644
index 000000000..0aa7b327e
--- /dev/null
+++ b/src/client/views/nodes/MenuIconBox.tsx
@@ -0,0 +1,33 @@
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { observer } from 'mobx-react';
+import * as React from 'react';
+import { createSchema, makeInterface } from '../../../fields/Schema';
+import { StrCast } from '../../../fields/Types';
+import { DocComponent } from '../DocComponent';
+import { FieldView, FieldViewProps } from './FieldView';
+import './MenuIconBox.scss';
+const MenuIconSchema = createSchema({
+    icon: "string"
+});
+
+type MenuIconDocument = makeInterface<[typeof MenuIconSchema]>;
+const MenuIconDocument = makeInterface(MenuIconSchema);
+@observer
+export class MenuIconBox extends DocComponent<FieldViewProps, MenuIconDocument>(MenuIconDocument) {
+    public static LayoutString(fieldKey: string) { return FieldView.LayoutString(MenuIconBox, fieldKey); }
+    _ref: React.RefObject<HTMLButtonElement> = React.createRef();
+
+    render() {
+
+        const color = this.props.backgroundColor?.(this.props.Document) === "lightgrey" ? "black" : "white";
+        const menuBTN = <div className="menuButton" style={{ backgroundColor: this.props.backgroundColor?.(this.props.Document) }}>
+            <div className="menuButton-wrap"
+                style={{ backgroundColor: this.props.backgroundColor?.(this.props.Document) }} >
+                <FontAwesomeIcon className="menuButton-icon" icon={StrCast(this.dataDoc.icon, "user") as any} color={color} size="lg" />
+                <div className="menuButton-label" style={{ color: color }}> {this.dataDoc.title} </div>
+            </div>
+        </div>;
+
+        return menuBTN;
+    }
+}
\ No newline at end of file
diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx
index c04c6c409..97f223c02 100644
--- a/src/client/views/nodes/PresBox.tsx
+++ b/src/client/views/nodes/PresBox.tsx
@@ -32,6 +32,7 @@ import { conformsTo } from "lodash";
 import { translate } from "googleapis/build/src/apis/translate";
 import { DragManager, dropActionType } from "../../util/DragManager";
 import { actionAsync } from "mobx-utils";
+import { SelectionManager } from "../../util/SelectionManager";
 
 type PresBoxSchema = makeInterface<[typeof documentSchema]>;
 const PresBoxDocument = makeInterface(documentSchema);
@@ -260,7 +261,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         const targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null);
         const srcContext = await DocCastAsync(targetDoc.context);
         const presCollection = Cast(this.layoutDoc.presCollection, Doc, null);
-        const collectionDocView = presCollection ? DocumentManager.Instance.getDocumentView(presCollection) : undefined;
+        const collectionDocView = presCollection ? await DocumentManager.Instance.getDocumentView(presCollection) : undefined;
         if (this.itemIndex >= 0) {
             if (targetDoc) {
                 if (srcContext) this.layoutDoc.presCollection = srcContext;
@@ -496,6 +497,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
     selectElement = (doc: Doc) => {
         // this._selectedArray = [];
         this.gotoDocument(this.childDocs.indexOf(doc), NumCast(this.itemIndex));
+        const view = DocumentManager.Instance.getDocumentView(doc);
+        view && SelectionManager.SelectDoc(view, false);
         // this._selectedArray.push(this.childDocs[this.childDocs.indexOf(doc)]);
         // console.log(this._selectedArray);
     }
@@ -504,8 +507,9 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
     @action
     multiSelect = (doc: Doc, ref: HTMLElement) => {
         this._selectedArray.push(this.childDocs[this.childDocs.indexOf(doc)]);
-        const ele = ref.getElementsByClassName("stacking");
         this._eleArray.push(ref);
+        const view = DocumentManager.Instance.getDocumentView(doc);
+        view && SelectionManager.SelectDoc(view, true);
     }
 
     //Shift click
@@ -517,6 +521,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
             for (let i = Math.min(this.itemIndex, this.childDocs.indexOf(doc)); i <= Math.max(this.itemIndex, this.childDocs.indexOf(doc)); i++) {
                 this._selectedArray.push(this.childDocs[i]);
                 this._eleArray.push(ref);
+                const view = DocumentManager.Instance.getDocumentView(doc);
+                view && SelectionManager.SelectDoc(view, true);
             }
         }
     }
diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx
index 958a37568..8ae71c035 100644
--- a/src/client/views/nodes/formattedText/DashFieldView.tsx
+++ b/src/client/views/nodes/formattedText/DashFieldView.tsx
@@ -190,7 +190,7 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna
             }
             list.map(c => c.heading).indexOf(this._fieldKey) === -1 && list.push(new SchemaHeaderField(this._fieldKey, "#f1efeb"));
             list.map(c => c.heading).indexOf("text") === -1 && list.push(new SchemaHeaderField("text", "#f1efeb"));
-            alias._pivotField = this._fieldKey;
+            alias._pivotField = this._fieldKey.startsWith("#") ? "#" : this._fieldKey;
             this.props.tbox.props.addDocTab(alias, "onRight");
         }
     }
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 627c6e363..fc65f34eb 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -1267,7 +1267,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         this.doLinkOnDeselect();
 
         // move the richtextmenu offscreen
-        if (!RichTextMenu.Instance.Pinned) RichTextMenu.Instance.delayHide();
+        //if (!RichTextMenu.Instance.Pinned) RichTextMenu.Instance.delayHide();
     }
 
     _lastTimedMark: Mark | undefined = undefined;
@@ -1346,7 +1346,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
     @computed get sidebarColor() { return StrCast(this.layoutDoc[this.props.fieldKey + "-backgroundColor"], StrCast(this.layoutDoc[this.props.fieldKey + "-backgroundColor"], "transparent")); }
     render() {
         TraceMobx();
-        const scale = this.props.ContentScaling() * NumCast(this.layoutDoc._viewScale, 1);
+        const scale = this.props.hideOnLeave ? 1 : this.props.ContentScaling() * NumCast(this.layoutDoc._viewScale, 1);
         const rounded = StrCast(this.layoutDoc.borderRounding) === "100%" ? "-rounded" : "";
         const interactive = Doc.GetSelectedTool() === InkTool.None && !this.layoutDoc.isBackground;
         setTimeout(() => this._editorView && RichTextMenu.Instance.updateFromDash(this._editorView, undefined, this.props), this.props.isSelected() ? 10 : 0); // need to make sure that we update a text box that is selected after updating the one that was deselected
diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx
index 7ccbfa051..f76707a79 100644
--- a/src/client/views/nodes/formattedText/RichTextMenu.tsx
+++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx
@@ -77,7 +77,8 @@ export default class RichTextMenu extends AntimodeMenu {
         super(props);
         RichTextMenu.Instance = this;
         this._canFade = false;
-        this.Pinned = BoolCast(Doc.UserDoc()["menuRichText-pinned"]);
+        //this.Pinned = BoolCast(Doc.UserDoc()["menuRichText-pinned"]);
+        this.Pinned = true;
 
         this.fontSizeOptions = [
             { mark: schema.marks.pFontSize.create({ fontSize: 7 }), title: "Set font size", label: "7pt", command: this.changeFontSize },
@@ -529,7 +530,7 @@ export default class RichTextMenu extends AntimodeMenu {
 
     indentParagraph(state: EditorState<any>, dispatch: any) {
         var tr = state.tr;
-        let headin = false;
+        const heading = false;
         state.doc.nodesBetween(state.selection.from, state.selection.to, (node, pos, parent, index) => {
             if (node.type === schema.nodes.paragraph || node.type === schema.nodes.heading) {
                 const nodeval = node.attrs.indent ? Number(node.attrs.indent) : undefined;
@@ -539,7 +540,7 @@ export default class RichTextMenu extends AntimodeMenu {
             }
             return true;
         });
-        !headin && dispatch?.(tr);
+        !heading && dispatch?.(tr);
         return true;
     }
 
@@ -920,16 +921,22 @@ export default class RichTextMenu extends AntimodeMenu {
     render() {
         TraceMobx();
         const row1 = <div className="antimodeMenu-row" key="row 1" style={{ display: this.collapsed ? "none" : undefined }}>{[
-            !this.collapsed ? this.getDragger() : (null),
-            !this.Pinned ? (null) : <div key="frag1"> {[
-                this.createButton("bold", "Bold", this.boldActive, toggleMark(schema.marks.strong)),
-                this.createButton("italic", "Italic", this.italicsActive, toggleMark(schema.marks.em)),
-                this.createButton("underline", "Underline", this.underlineActive, toggleMark(schema.marks.underline)),
-                this.createButton("strikethrough", "Strikethrough", this.strikethroughActive, toggleMark(schema.marks.strikethrough)),
-                this.createButton("superscript", "Superscript", this.superscriptActive, toggleMark(schema.marks.superscript)),
-                this.createButton("subscript", "Subscript", this.subscriptActive, toggleMark(schema.marks.subscript)),
-                <div className="richTextMenu-divider" key="divider" />
-            ]}</div>,
+            //!this.collapsed ? this.getDragger() : (null),
+            // !this.Pinned ? (null) : <div key="frag1"> {[
+            //     this.createButton("bold", "Bold", this.boldActive, toggleMark(schema.marks.strong)),
+            //     this.createButton("italic", "Italic", this.italicsActive, toggleMark(schema.marks.em)),
+            //     this.createButton("underline", "Underline", this.underlineActive, toggleMark(schema.marks.underline)),
+            //     this.createButton("strikethrough", "Strikethrough", this.strikethroughActive, toggleMark(schema.marks.strikethrough)),
+            //     this.createButton("superscript", "Superscript", this.superscriptActive, toggleMark(schema.marks.superscript)),
+            //     this.createButton("subscript", "Subscript", this.subscriptActive, toggleMark(schema.marks.subscript)),
+            //     <div className="richTextMenu-divider" key="divider" />
+            // ]}</div>,
+            this.createButton("bold", "Bold", this.boldActive, toggleMark(schema.marks.strong)),
+            this.createButton("italic", "Italic", this.italicsActive, toggleMark(schema.marks.em)),
+            this.createButton("underline", "Underline", this.underlineActive, toggleMark(schema.marks.underline)),
+            this.createButton("strikethrough", "Strikethrough", this.strikethroughActive, toggleMark(schema.marks.strikethrough)),
+            this.createButton("superscript", "Superscript", this.superscriptActive, toggleMark(schema.marks.superscript)),
+            this.createButton("subscript", "Subscript", this.subscriptActive, toggleMark(schema.marks.subscript)),
             this.createColorButton(),
             this.createHighlighterButton(),
             this.createLinkButton(),
@@ -957,16 +964,16 @@ export default class RichTextMenu extends AntimodeMenu {
                 this.createButton("minus", "Horizontal Rule", undefined, this.insertHorizontalRule),
                 <div className="richTextMenu-divider" key="divider 5" />,]}
             </div>
-            <div key="collapser">
-                {/* <div key="collapser">
+            {/* <div key="collapser">
+                {<div key="collapser">
                     <button className="antimodeMenu-button" key="collapse menu" title="Collapse menu" onClick={this.toggleCollapse} style={{ backgroundColor: this.collapsed ? "#121212" : "", width: 25 }}>
                         <FontAwesomeIcon icon="chevron-left" size="lg" style={{ transitionProperty: "transform", transitionDuration: "0.3s", transform: `rotate(${this.collapsed ? 180 : 0}deg)` }} />
                     </button>
-                </div> */}
+                </div> }
                 <button className="antimodeMenu-button" key="pin menu" title="Pin menu" onClick={this.toggleMenuPin} style={{ backgroundColor: this.Pinned ? "#121212" : "", display: this.collapsed ? "none" : undefined }}>
                     <FontAwesomeIcon icon="thumbtack" size="lg" style={{ transitionProperty: "transform", transitionDuration: "0.1s", transform: `rotate(${this.Pinned ? 45 : 0}deg)` }} />
                 </button>
-            </div>
+            </div> */}
         </div>;
 
         return (
diff --git a/src/client/views/nodes/formattedText/nodes_rts.ts b/src/client/views/nodes/formattedText/nodes_rts.ts
index 0eca6d753..1616500f6 100644
--- a/src/client/views/nodes/formattedText/nodes_rts.ts
+++ b/src/client/views/nodes/formattedText/nodes_rts.ts
@@ -79,14 +79,14 @@ export const nodes: { [index: string]: NodeSpec } = {
         { tag: "h5", attrs: { level: 5 } },
         { tag: "h6", attrs: { level: 6 } }],
         toDOM(node) {
-            var dom = toParagraphDOM(node) as any;
-            var level = node.attrs.level || 1;
+            const dom = toParagraphDOM(node) as any;
+            const level = node.attrs.level || 1;
             dom[0] = 'h' + level;
             return dom;
         },
         getAttrs(dom: any) {
-            var attrs = getParagraphNodeAttrs(dom) as any;
-            var level = Number(dom.nodeName.substring(1)) || 1;
+            const attrs = getParagraphNodeAttrs(dom) as any;
+            const level = Number(dom.nodeName.substring(1)) || 1;
             attrs.level = level;
             return attrs;
         }
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 43e74ff61..85fc63074 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -528,10 +528,10 @@ export namespace Doc {
             const cfield = ComputedField.WithoutComputed(() => FieldValue(doc[key]));
             const field = ProxyField.WithoutProxy(() => doc[key]);
             const copyObjectField = async (field: ObjectField) => {
-                const list = await Cast(doc[key], listSpec(Doc));
+                const list = Cast(doc[key], listSpec(Doc));
                 const docs = list && (await DocListCastAsync(list))?.filter(d => d instanceof Doc);
                 if (docs !== undefined && docs.length) {
-                    const clones = await Promise.all(docs.map(async d => await Doc.makeClone(d as Doc, cloneMap, rtfs, exclusions, dontCreate)));
+                    const clones = await Promise.all(docs.map(async d => Doc.makeClone(d, cloneMap, rtfs, exclusions, dontCreate)));
                     !dontCreate && assignKey(new List<Doc>(clones));
                 } else if (doc[key] instanceof Doc) {
                     assignKey(key.includes("layout[") ? undefined : key.startsWith("layout") ? doc[key] as Doc : await Doc.makeClone(doc[key] as Doc, cloneMap, rtfs, exclusions, dontCreate)); // reference documents except copy documents that are expanded teplate fields 
@@ -625,7 +625,7 @@ export namespace Doc {
         Array.from(map.entries()).forEach(f => docs[f[0]] = f[1]);
         const docString = JSON.stringify({ id: doc[Id], docs }, replacer);
 
-        var zip = new JSZip();
+        const zip = new JSZip();
 
         zip.file(doc.title + ".json", docString);
 
diff --git a/src/server/ActionUtilities.ts b/src/server/ActionUtilities.ts
index 60f66c878..fd9bc0c83 100644
--- a/src/server/ActionUtilities.ts
+++ b/src/server/ActionUtilities.ts
@@ -1,11 +1,11 @@
-import { readFile, writeFile, exists, mkdir, unlink, createWriteStream } from 'fs';
-import { ExecOptions } from 'shelljs';
 import { exec } from 'child_process';
-import * as path from 'path';
-import * as rimraf from "rimraf";
-import { yellow, Color } from 'colors';
+import { Color, yellow } from 'colors';
+import { createWriteStream, exists, mkdir, readFile, unlink, writeFile } from 'fs';
 import * as nodemailer from "nodemailer";
 import { MailOptions } from "nodemailer/lib/json-transport";
+import * as path from 'path';
+import * as rimraf from "rimraf";
+import { ExecOptions } from 'shelljs';
 import Mail = require('nodemailer/lib/mailer');
 
 const projectRoot = path.resolve(__dirname, "../../");
diff --git a/src/server/ApiManagers/UtilManager.ts b/src/server/ApiManagers/UtilManager.ts
index e2cd88726..e657866ce 100644
--- a/src/server/ApiManagers/UtilManager.ts
+++ b/src/server/ApiManagers/UtilManager.ts
@@ -6,7 +6,6 @@ import { exec } from 'child_process';
 
 // const recommender = new Recommender();
 // recommender.testModel();
-import executeImport from "../../scraping/buxton/final/BuxtonImporter";
 
 export default class UtilManager extends ApiManager {
 
diff --git a/src/server/DashUploadUtils.ts b/src/server/DashUploadUtils.ts
index 2bf4c1956..890fb6f6d 100644
--- a/src/server/DashUploadUtils.ts
+++ b/src/server/DashUploadUtils.ts
@@ -1,23 +1,22 @@
-import { unlinkSync, createWriteStream, readFileSync, rename, writeFile, existsSync } from 'fs';
-import { Utils } from '../Utils';
-import * as path from 'path';
-import * as sharp from 'sharp';
-import request = require('request-promise');
+import { red } from 'colors';
 import { ExifImage } from 'exif';
-import { Opt } from '../fields/Doc';
-import { AcceptibleMedia, Upload } from './SharedMediaTypes';
-import { filesDirectory, publicDirectory } from '.';
 import { File } from 'formidable';
+import { createWriteStream, existsSync, readFileSync, rename, unlinkSync, writeFile } from 'fs';
+import * as path from 'path';
 import { basename } from "path";
-import { createIfNotExists } from './ActionUtilities';
+import * as sharp from 'sharp';
+import { Stream } from 'stream';
+import { filesDirectory, publicDirectory } from '.';
+import { Opt } from '../fields/Doc';
 import { ParsedPDF } from "../server/PdfTypes";
+import { Utils } from '../Utils';
+import { createIfNotExists } from './ActionUtilities';
+import { clientPathToFile, Directory, pathToDirectory, serverPathToFile } from './ApiManagers/UploadManager';
+import { resolvedServerUrl } from "./server_Initialization";
+import { AcceptibleMedia, Upload } from './SharedMediaTypes';
+import request = require('request-promise');
 const parse = require('pdf-parse');
-import { Directory, serverPathToFile, clientPathToFile, pathToDirectory } from './ApiManagers/UploadManager';
-import { red } from 'colors';
-import { Stream } from 'stream';
-import { resolvedPorts } from './server_Initialization';
 const requestImageSize = require("../client/util/request-image-size");
-import { resolvedServerUrl } from "./server_Initialization";
 
 export enum SizeSuffix {
     Small = "_s",
diff --git a/src/server/GarbageCollector.ts b/src/server/GarbageCollector.ts
index 24745cbb4..a9a3b0481 100644
--- a/src/server/GarbageCollector.ts
+++ b/src/server/GarbageCollector.ts
@@ -1,9 +1,9 @@
-import { Database } from './database';
-
-import * as path from 'path';
 import * as fs from 'fs';
+import * as path from 'path';
+import { Database } from './database';
 import { Search } from './Search';
 
+
 function addDoc(doc: any, ids: string[], files: { [name: string]: string[] }) {
     for (const key in doc) {
         if (!doc.hasOwnProperty(key)) {
diff --git a/src/server/MemoryDatabase.ts b/src/server/MemoryDatabase.ts
index 1f1d702d9..7f477327e 100644
--- a/src/server/MemoryDatabase.ts
+++ b/src/server/MemoryDatabase.ts
@@ -1,6 +1,7 @@
-import { IDatabase, DocumentsCollection } from './IDatabase';
-import { Transferable } from './Message';
+import { DH_CHECK_P_NOT_SAFE_PRIME } from 'constants';
 import * as mongodb from 'mongodb';
+import { DocumentsCollection, IDatabase } from './IDatabase';
+import { Transferable } from './Message';
 
 export class MemoryDatabase implements IDatabase {
 
diff --git a/src/server/Message.ts b/src/server/Message.ts
index ff0381fd3..59b24cd82 100644
--- a/src/server/Message.ts
+++ b/src/server/Message.ts
@@ -1,6 +1,6 @@
-import { Utils } from "../Utils";
 import { Point } from "../pen-gestures/ndollar";
 import { AnalysisResult, ImportResults } from "../scraping/buxton/final/BuxtonImporter";
+import { Utils } from "../Utils";
 
 export class Message<T> {
     private _name: string;
diff --git a/src/server/ProcessFactory.ts b/src/server/ProcessFactory.ts
index acb8b3a99..63682368f 100644
--- a/src/server/ProcessFactory.ts
+++ b/src/server/ProcessFactory.ts
@@ -1,8 +1,8 @@
-import { existsSync, mkdirSync } from "fs";
-import { pathFromRoot, fileDescriptorFromStream } from './ActionUtilities';
-import rimraf = require("rimraf");
 import { ChildProcess, spawn, StdioOptions } from "child_process";
+import { existsSync, mkdirSync } from "fs";
 import { Stream } from "stream";
+import { fileDescriptorFromStream, pathFromRoot } from './ActionUtilities';
+import rimraf = require("rimraf");
 
 export namespace ProcessFactory {
 
diff --git a/src/server/Recommender.ts b/src/server/Recommender.ts
deleted file mode 100644
index 935ec3871..000000000
--- a/src/server/Recommender.ts
+++ /dev/null
@@ -1,133 +0,0 @@
-// //import { Doc } from "../fields/Doc";
-// //import { StrCast } from "../fields/Types";
-// //import { List } from "../fields/List";
-// //import { CognitiveServices } from "../client/cognitive_services/CognitiveServices";
-
-// // var w2v = require('word2vec');
-// var assert = require('assert');
-// var arxivapi = require('arxiv-api-node');
-// import requestPromise = require("request-promise");
-// import * as use from '@tensorflow-models/universal-sentence-encoder';
-// import { Tensor } from "@tensorflow/tfjs-core/dist/tensor";
-// require('@tensorflow/tfjs-node');
-
-// //http://gnuwin32.sourceforge.net/packages/make.htm
-
-// export class Recommender {
-
-//     private _model: any;
-//     static Instance: Recommender;
-//     private dimension: number = 0;
-//     private choice: string = ""; // Tensorflow or Word2Vec
-
-//     constructor() {
-//         Recommender.Instance = this;
-//     }
-
-//     /***
-//      * Loads pre-trained model from TF
-//      */
-
-//     public async loadTFModel() {
-//         let self = this;
-//         return new Promise(res => {
-//             use.load().then(model => {
-//                 self.choice = "TF";
-//                 self._model = model;
-//                 self.dimension = 512;
-//                 res(model);
-//             });
-//         }
-
-//         );
-//     }
-
-//     /***
-//      * Loads pre-trained model from word2vec
-//      */
-
-//     // private loadModel(): Promise<any> {
-//     //     let self = this;
-//     //     return new Promise(res => {
-//     //         w2v.loadModel("./node_modules/word2vec/examples/fixtures/vectors.txt", function (err: any, model: any) {
-//     //             self.choice = "WV";
-//     //             self._model = model;
-//     //             self.dimension = model.size;
-//     //             res(model);
-//     //         });
-//     //     });
-//     // }
-
-//     /***
-//      * Testing
-//      */
-
-//     public async testModel() {
-//         if (!this._model) {
-//             await this.loadTFModel();
-//         }
-//         if (this._model) {
-//             if (this.choice === "WV") {
-//                 let similarity = this._model.similarity('father', 'mother');
-//             }
-//             else if (this.choice === "TF") {
-//                 const model = this._model as use.UniversalSentenceEncoder;
-//                 // Embed an array of sentences.
-//                 const sentences = [
-//                     'Hello.',
-//                     'How are you?'
-//                 ];
-//                 const embeddings = await this.vectorize(sentences);
-//                 if (embeddings) embeddings.print(true /*verbose*/);
-//                 // model.embed(sentences).then(embeddings => {
-//                 //     // `embeddings` is a 2D tensor consisting of the 512-dimensional embeddings for each sentence.
-//                 //     // So in this example `embeddings` has the shape [2, 512].
-//                 //     embeddings.print(true /* verbose */);
-//                 // });
-//             }
-//         }
-//         else {
-//             console.log("model not found :(");
-//         }
-//     }
-
-//     /***
-//      * Uses model to convert words to vectors
-//      */
-
-//     public async vectorize(text: string[]): Promise<Tensor | undefined> {
-//         if (!this._model) {
-//             await this.loadTFModel();
-//         }
-//         if (this._model) {
-//             if (this.choice === "WV") {
-//                 let word_vecs = this._model.getVectors(text);
-//                 return word_vecs;
-//             }
-//             else if (this.choice === "TF") {
-//                 const model = this._model as use.UniversalSentenceEncoder;
-//                 return new Promise<Tensor>(res => {
-//                     model.embed(text).then(embeddings => {
-//                         res(embeddings);
-//                     });
-//                 });
-
-//             }
-//         }
-//     }
-
-//     // public async trainModel() {
-//     //     w2v.word2vec("./node_modules/word2vec/examples/eng_news-typical_2016_1M-sentences.txt", './node_modules/word2vec/examples/my_phrases.txt', {
-//     //         cbow: 1,
-//     //         size: 200,
-//     //         window: 8,
-//     //         negative: 25,
-//     //         hs: 0,
-//     //         sample: 1e-4,
-//     //         threads: 20,
-//     //         iter: 200,
-//     //         minCount: 2
-//     //     });
-//     // }
-
-// }
diff --git a/src/server/RouteManager.ts b/src/server/RouteManager.ts
index 1a2340afc..78b75d6be 100644
--- a/src/server/RouteManager.ts
+++ b/src/server/RouteManager.ts
@@ -1,8 +1,8 @@
-import RouteSubscriber from "./RouteSubscriber";
-import { DashUserModel } from "./authentication/DashUserModel";
-import { Request, Response, Express } from 'express';
-import { cyan, red, green } from 'colors';
+import { cyan, green, red } from 'colors';
+import { Express, Request, Response } from 'express';
 import { AdminPriviliges } from ".";
+import { DashUserModel } from "./authentication/DashUserModel";
+import RouteSubscriber from "./RouteSubscriber";
 
 export enum Method {
     GET,
diff --git a/src/server/Search.ts b/src/server/Search.ts
index 21064e520..decd1f5b1 100644
--- a/src/server/Search.ts
+++ b/src/server/Search.ts
@@ -1,5 +1,5 @@
-import * as rp from 'request-promise';
 import { red } from 'colors';
+import * as rp from 'request-promise';
 
 const pathTo = (relative: string) => `http://localhost:8983/solr/dash/${relative}`;
 
diff --git a/src/server/database.ts b/src/server/database.ts
index 2372cbcf2..b7aa77f5d 100644
--- a/src/server/database.ts
+++ b/src/server/database.ts
@@ -1,11 +1,11 @@
 import * as mongodb from 'mongodb';
-import { Transferable } from './Message';
+import * as mongoose from 'mongoose';
 import { Opt } from '../fields/Doc';
-import { Utils, emptyFunction } from '../Utils';
+import { emptyFunction, Utils } from '../Utils';
 import { GoogleApiServerUtils } from './apis/google/GoogleApiServerUtils';
-import { IDatabase, DocumentsCollection } from './IDatabase';
+import { DocumentsCollection, IDatabase } from './IDatabase';
 import { MemoryDatabase } from './MemoryDatabase';
-import * as mongoose from 'mongoose';
+import { Transferable } from './Message';
 import { Upload } from './SharedMediaTypes';
 
 export namespace Database {
diff --git a/src/server/downsize.ts b/src/server/downsize.ts
index 5cd709fa3..382994e2d 100644
--- a/src/server/downsize.ts
+++ b/src/server/downsize.ts
@@ -1,5 +1,5 @@
-import * as sharp from 'sharp';
 import * as fs from 'fs';
+import * as sharp from 'sharp';
 
 const folder = "./src/server/public/files/";
 const pngTypes = ["png", "PNG"];
diff --git a/src/server/index.ts b/src/server/index.ts
index 9af4b00bc..9185e3c5e 100644
--- a/src/server/index.ts
+++ b/src/server/index.ts
@@ -1,29 +1,29 @@
 require('dotenv').config();
-import { GoogleApiServerUtils } from "./apis/google/GoogleApiServerUtils";
+import { yellow } from "colors";
 import * as mobileDetect from 'mobile-detect';
 import * as path from 'path';
-import { Database } from './database';
-import { DashUploadUtils } from './DashUploadUtils';
-import RouteSubscriber from './RouteSubscriber';
-import initializeServer, { resolvedPorts } from './server_Initialization';
-import RouteManager, { Method, _success, _permission_denied, _error, _invalid, PublicHandler } from './RouteManager';
 import * as qs from 'query-string';
-import UtilManager from './ApiManagers/UtilManager';
-import { SearchManager } from './ApiManagers/SearchManager';
-import UserManager from './ApiManagers/UserManager';
-import DownloadManager from './ApiManagers/DownloadManager';
-import { GoogleCredentialsLoader, SSL } from './apis/google/CredentialsLoader';
-import DeleteManager from "./ApiManagers/DeleteManager";
-import PDFManager from "./ApiManagers/PDFManager";
-import UploadManager from "./ApiManagers/UploadManager";
 import { log_execution } from "./ActionUtilities";
+import DeleteManager from "./ApiManagers/DeleteManager";
+import DownloadManager from './ApiManagers/DownloadManager';
 import GeneralGoogleManager from "./ApiManagers/GeneralGoogleManager";
-import HypothesisManager from "./ApiManagers/HypothesisManager";
 import GooglePhotosManager from "./ApiManagers/GooglePhotosManager";
-import { Logger } from "./ProcessFactory";
-import { yellow } from "colors";
+import HypothesisManager from "./ApiManagers/HypothesisManager";
+import PDFManager from "./ApiManagers/PDFManager";
+import { SearchManager } from './ApiManagers/SearchManager';
 import SessionManager from "./ApiManagers/SessionManager";
+import UploadManager from "./ApiManagers/UploadManager";
+import UserManager from './ApiManagers/UserManager';
+import UtilManager from './ApiManagers/UtilManager';
+import { GoogleCredentialsLoader, SSL } from './apis/google/CredentialsLoader';
+import { GoogleApiServerUtils } from "./apis/google/GoogleApiServerUtils";
 import { AppliedSessionAgent } from "./DashSession/Session/agents/applied_session_agent";
+import { DashUploadUtils } from './DashUploadUtils';
+import { Database } from './database';
+import { Logger } from "./ProcessFactory";
+import RouteManager, { Method, PublicHandler } from './RouteManager';
+import RouteSubscriber from './RouteSubscriber';
+import initializeServer, { resolvedPorts } from './server_Initialization';
 
 export const AdminPriviliges: Map<string, boolean> = new Map();
 export const onWindows = process.platform === "win32";
diff --git a/src/server/server_Initialization.ts b/src/server/server_Initialization.ts
index 744d4547b..e40f2b8e5 100644
--- a/src/server/server_Initialization.ts
+++ b/src/server/server_Initialization.ts
@@ -1,31 +1,31 @@
+import * as bodyParser from 'body-parser';
+import { blue, yellow } from 'colors';
+import * as cookieParser from 'cookie-parser';
+import * as cors from "cors";
 import * as express from 'express';
-import * as expressValidator from 'express-validator';
 import * as session from 'express-session';
+import * as expressValidator from 'express-validator';
+import * as fs from 'fs';
+import { Server as HttpServer } from "http";
+import { createServer, Server as HttpsServer } from "https";
 import * as passport from 'passport';
-import * as bodyParser from 'body-parser';
-import * as cookieParser from 'cookie-parser';
-import expressFlash = require('express-flash');
-import flash = require('connect-flash');
-import { Database } from './database';
-import { getForgot, getLogin, getLogout, getReset, getSignup, postForgot, postLogin, postReset, postSignup } from './authentication/AuthenticationManager';
-const MongoStore = require('connect-mongo')(session);
-import RouteManager from './RouteManager';
-import { WebSocket } from './websocket';
+import * as request from 'request';
 import * as webpack from 'webpack';
-const config = require('../../webpack.config');
-const compiler = webpack(config);
 import * as wdm from 'webpack-dev-middleware';
 import * as whm from 'webpack-hot-middleware';
-import * as fs from 'fs';
-import * as request from 'request';
-import RouteSubscriber from './RouteSubscriber';
 import { publicDirectory } from '.';
 import { logPort } from './ActionUtilities';
-import { blue, yellow } from 'colors';
-import * as cors from "cors";
-import { createServer, Server as HttpsServer } from "https";
-import { Server as HttpServer } from "http";
 import { SSL } from './apis/google/CredentialsLoader';
+import { getForgot, getLogin, getLogout, getReset, getSignup, postForgot, postLogin, postReset, postSignup } from './authentication/AuthenticationManager';
+import { Database } from './database';
+import RouteManager from './RouteManager';
+import RouteSubscriber from './RouteSubscriber';
+import { WebSocket } from './websocket';
+import expressFlash = require('express-flash');
+import flash = require('connect-flash');
+const MongoStore = require('connect-mongo')(session);
+const config = require('../../webpack.config');
+const compiler = webpack(config);
 
 /* RouteSetter is a wrapper around the server that prevents the server
    from being exposed. */
diff --git a/src/server/websocket.ts b/src/server/websocket.ts
index f63a35e43..d5f89a750 100644
--- a/src/server/websocket.ts
+++ b/src/server/websocket.ts
@@ -1,21 +1,20 @@
-import * as fs from 'fs';
-import { logPort } from './ActionUtilities';
-import { Utils } from "../Utils";
-import { MessageStore, Transferable, Types, Diff, YoutubeQueryInput, YoutubeQueryTypes, GestureContent, MobileInkOverlayContent, UpdateMobileInkOverlayPositionContent, MobileDocumentUploadContent, RoomMessage } from "./Message";
-import { Client } from "./Client";
-import { Socket } from "socket.io";
-import { Database } from "./database";
-import { Search } from "./Search";
-import * as sio from 'socket.io';
-import YoutubeApi from "./apis/youtube/youtubeApiSample";
-import { GoogleCredentialsLoader, SSL } from "./apis/google/CredentialsLoader";
-import { timeMap } from "./ApiManagers/UserManager";
 import { green } from "colors";
+import * as express from "express";
+import { createServer, Server } from "https";
 import { networkInterfaces } from "os";
+import * as sio from 'socket.io';
+import { Socket } from "socket.io";
 import executeImport from "../scraping/buxton/final/BuxtonImporter";
+import { Utils } from "../Utils";
+import { logPort } from './ActionUtilities';
+import { timeMap } from "./ApiManagers/UserManager";
+import { GoogleCredentialsLoader, SSL } from "./apis/google/CredentialsLoader";
+import YoutubeApi from "./apis/youtube/youtubeApiSample";
+import { Client } from "./Client";
+import { Database } from "./database";
 import { DocumentsCollection } from "./IDatabase";
-import { createServer, Server } from "https";
-import * as express from "express";
+import { Diff, GestureContent, MessageStore, MobileDocumentUploadContent, MobileInkOverlayContent, Transferable, Types, UpdateMobileInkOverlayPositionContent, YoutubeQueryInput, YoutubeQueryTypes } from "./Message";
+import { Search } from "./Search";
 import { resolvedPorts } from './server_Initialization';
 
 export namespace WebSocket {
-- 
cgit v1.2.3-70-g09d2

