From 888ddd78737781f8a2d045b5f1e41788c512c94d Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 8 Sep 2023 17:02:49 -0400
Subject: don't remove current recording from overlay, added closeOnSelect
 option  for dropdown.   place recording box on screen.  fixe overlayView to
 keep views on screen. fixed schema view checkboxes. don't cause tab to
 rerender when colelctoin type changes.  add dropdown to filter indicator to
 find filters.

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

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

diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx
index 42db0b9be..d939470e9 100644
--- a/src/client/views/PropertiesButtons.tsx
+++ b/src/client/views/PropertiesButtons.tsx
@@ -376,6 +376,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
             <Dropdown
                 tooltip={'Choose onClick behavior'}
                 items={items}
+                closeOnSelect={true}
                 selectedVal={this.onClickVal}
                 setSelectedVal={val => this.handleOptionChange(val as string)}
                 title={'Choose onClick behaviour'}
-- 
cgit v1.2.3-70-g09d2


From 507cdb40d5553c8a325ddb158b9a1f4e5672ac15 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 11 Sep 2023 22:35:42 -0400
Subject: moved edit on click script to developer. fixed highlight options for
 My text.  enabled chromeHidden for all doc types and applied it to RTF text
 boxes.  updated sliders in properties view to undo properly and to autorange,
 and cleaned up ode.

---
 package-lock.json                                  |  30 ++--
 package.json                                       |   2 +-
 src/client/views/PropertiesButtons.tsx             |   2 +-
 src/client/views/PropertiesSection.tsx             |   6 +-
 src/client/views/PropertiesView.scss               |   3 +-
 src/client/views/PropertiesView.tsx                | 186 ++++++++++-----------
 src/client/views/nodes/DocumentView.tsx            |   4 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx |  10 +-
 src/client/views/nodes/formattedText/marks_rts.ts  |   2 +-
 src/fields/DocSymbols.ts                           |   2 +-
 10 files changed, 115 insertions(+), 132 deletions(-)

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

diff --git a/package-lock.json b/package-lock.json
index 6055e9d1e..d15959b7d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2852,9 +2852,9 @@
             }
         },
         "@floating-ui/dom": {
-            "version": "1.5.1",
-            "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.5.1.tgz",
-            "integrity": "sha512-KwvVcPSXg6mQygvA1TjbN/gh///36kKtllIF8SUm0qpFj8+rvYrpvlYdL1JoA71SHpDqgSSdGOSoQ0Mp3uY5aw==",
+            "version": "1.5.2",
+            "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.5.2.tgz",
+            "integrity": "sha512-6ArmenS6qJEWmwzczWyhvrXRdI/rI78poBcW0h/456+onlabit+2G+QxHx5xTOX60NBJQXjsCLFbW2CmsXpUog==",
             "requires": {
                 "@floating-ui/core": "^1.4.1",
                 "@floating-ui/utils": "^0.1.1"
@@ -2869,9 +2869,9 @@
             }
         },
         "@floating-ui/utils": {
-            "version": "0.1.1",
-            "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.1.1.tgz",
-            "integrity": "sha512-m0G6wlnhm/AX0H12IOWtK8gASEMffnX08RtKkCgTdHb9JpHKGloI7icFfLg9ZmQeavcvR0PKmzxClyuFPSjKWw=="
+            "version": "0.1.2",
+            "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.1.2.tgz",
+            "integrity": "sha512-ou3elfqG/hZsbmF4bxeJhPHIf3G2pm0ujc39hYEZrfVqt7Vk/Zji6CXc3W0pmYM8BW1g40U+akTl9DKZhFhInQ=="
         },
         "@fortawesome/fontawesome-common-types": {
             "version": "6.4.0",
@@ -6687,9 +6687,9 @@
             }
         },
         "browndash-components": {
-            "version": "0.1.25",
-            "resolved": "https://registry.npmjs.org/browndash-components/-/browndash-components-0.1.25.tgz",
-            "integrity": "sha512-YgzUsfeUKwtaOLRYNDcxybZG2Ip7KSQV38VbUrgC+ycwOX/tzq9IWlfw2z4h/EVuVcq+ERCaBS4pb3mMU6pKGQ==",
+            "version": "0.1.35",
+            "resolved": "https://registry.npmjs.org/browndash-components/-/browndash-components-0.1.35.tgz",
+            "integrity": "sha512-xA4ACEppnDe5ThnUZPn9vo4W/KeZJZT5EFWh2tM0IsH/ZfcOhJopGfV6ZoIHHpvS5f/zi6l7YJuWaxd+aK5arg==",
             "requires": {
                 "@emotion/react": "^11.11.1",
                 "@emotion/styled": "^11.11.0",
@@ -10146,14 +10146,14 @@
                     }
                 },
                 "caniuse-lite": {
-                    "version": "1.0.30001529",
-                    "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001529.tgz",
-                    "integrity": "sha512-n2pUQYGAkrLG4QYj2desAh+NqsJpHbNmVZz87imptDdxLAtjxary7Df/psdfyDGmskJK/9Dt9cPnx5RZ3CU4Og=="
+                    "version": "1.0.30001532",
+                    "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001532.tgz",
+                    "integrity": "sha512-FbDFnNat3nMnrROzqrsg314zhqN5LGQ1kyyMk2opcrwGbVGpHRhgCWtAgD5YJUqNAiQ+dklreil/c3Qf1dfCTw=="
                 },
                 "electron-to-chromium": {
-                    "version": "1.4.513",
-                    "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.513.tgz",
-                    "integrity": "sha512-cOB0xcInjm+E5qIssHeXJ29BaUyWpMyFKT5RB3bsLENDheCja0wMkHJyiPl0NBE/VzDI7JDuNEQWhe6RitEUcw=="
+                    "version": "1.4.515",
+                    "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.515.tgz",
+                    "integrity": "sha512-VTq6vjk3kCfG2qdzQRd/i9dIyVVm0dbtZIgFzrLgfB73mXDQT2HPKVRc1EoZcAVUv9XhXAu08DWqJuababdGGg=="
                 }
             }
         },
diff --git a/package.json b/package.json
index 9f0b91628..92ebf0b0f 100644
--- a/package.json
+++ b/package.json
@@ -178,7 +178,7 @@
         "body-parser": "^1.19.2",
         "bootstrap": "^4.6.1",
         "brotli": "^1.3.3",
-        "browndash-components": "^0.1.25",
+        "browndash-components": "^0.1.35",
         "browser-assert": "^1.2.1",
         "bson": "^4.6.1",
         "canvas": "^2.9.3",
diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx
index d939470e9..8b2b77aca 100644
--- a/src/client/views/PropertiesButtons.tsx
+++ b/src/client/views/PropertiesButtons.tsx
@@ -512,7 +512,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
                 {toggle(this.layout_autoHeightButton, { display: !isText && !isStacking && !isTree ? 'none' : '' })}
                 {toggle(this.maskButton, { display: !isInk ? 'none' : '' })}
                 {toggle(this.hideImageButton, { display: !isImage ? 'none' : '' })}
-                {toggle(this.chromeButton, { display: !isCollection || isNovice ? 'none' : '' })}
+                {toggle(this.chromeButton, { display: isNovice ? 'none' : '' })}
                 {toggle(this.gridButton, { display: !isCollection ? 'none' : '' })}
                 {/* {toggle(this.groupButton, { display: isTabView || !isCollection ? 'none' : '' })} */}
                 {toggle(this.snapButton, { display: !isCollection ? 'none' : '' })}
diff --git a/src/client/views/PropertiesSection.tsx b/src/client/views/PropertiesSection.tsx
index b72e048df..0e7cd7e92 100644
--- a/src/client/views/PropertiesSection.tsx
+++ b/src/client/views/PropertiesSection.tsx
@@ -8,7 +8,7 @@ import { StrCast } from '../../fields/Types';
 
 export interface PropertiesSectionProps {
     title: string;
-    content?: JSX.Element | string | null;
+    children?: JSX.Element | string | null;
     isOpen: boolean;
     setIsOpen: (bool: boolean) => any;
     inSection?: boolean;
@@ -33,7 +33,7 @@ export class PropertiesSection extends React.Component<PropertiesSectionProps> {
     @observable isDouble: boolean = false;
 
     render() {
-        if (this.props.content === undefined || this.props.content === null) return null;
+        if (this.props.children === undefined || this.props.children === null) return null;
         else
             return (
                 <div className="propertiesView-section" onPointerEnter={action(() => this.props.setInSection && this.props.setInSection(true))} onPointerLeave={action(() => this.props.setInSection && this.props.setInSection(false))}>
@@ -58,7 +58,7 @@ export class PropertiesSection extends React.Component<PropertiesSectionProps> {
                             <FontAwesomeIcon icon={this.props.isOpen ? 'caret-down' : 'caret-right'} size="lg" />
                         </div>
                     </div>
-                    {!this.props.isOpen ? null : <div className="propertiesView-content">{this.props.content}</div>}
+                    {!this.props.isOpen ? null : <div className="propertiesView-content">{this.props.children}</div>}
                 </div>
             );
     }
diff --git a/src/client/views/PropertiesView.scss b/src/client/views/PropertiesView.scss
index 510defce4..2da2ec568 100644
--- a/src/client/views/PropertiesView.scss
+++ b/src/client/views/PropertiesView.scss
@@ -46,8 +46,7 @@
     }
 
     .propertiesView-info {
-        margin-top: 20;
-        margin-right: 10;
+        margin-top: -5;
         float: right;
         font-size: 20;
         path {
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 9cc75b1c6..b25ac7903 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -5,7 +5,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { Checkbox, Tooltip } from '@material-ui/core';
 import { Colors, EditableText, IconButton, NumberInput, Size, Slider, Type } from 'browndash-components';
 import { concat } from 'lodash';
-import { action, computed, IReactionDisposer, observable, reaction } from 'mobx';
+import { action, computed, IReactionDisposer, observable, reaction, trace } from 'mobx';
 import { observer } from 'mobx-react';
 import { ColorState, SketchPicker } from 'react-color';
 import * as Icons from 'react-icons/bs'; //{BsCollectionFill, BsFillFileEarmarkImageFill} from "react-icons/bs"
@@ -783,39 +783,39 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     }
 
     @computed get shapeXps() {
-        return this.getField('x');
+        return NumCast(this.selectedDoc?.x);
     }
     @computed get shapeYps() {
-        return this.getField('y');
+        return NumCast(this.selectedDoc?.y);
     }
     @computed get shapeHgt() {
-        return this.getField('_height');
+        return NumCast(this.selectedDoc?._height);
     }
     @computed get shapeWid() {
-        return this.getField('_width');
+        return NumCast(this.selectedDoc?._width);
     }
     set shapeXps(value) {
-        this.selectedDoc && (this.selectedDoc.x = Number(value));
+        this.selectedDoc && (this.selectedDoc.x = Math.round(value * 100) / 100);
     }
     set shapeYps(value) {
-        this.selectedDoc && (this.selectedDoc.y = Number(value));
+        this.selectedDoc && (this.selectedDoc.y = Math.round(value * 100) / 100);
     }
     set shapeWid(value) {
-        this.selectedDoc && (this.selectedDoc._width = Number(value));
+        this.selectedDoc && (this.selectedDoc._width = Math.round(value * 100) / 100);
     }
     set shapeHgt(value) {
-        this.selectedDoc && (this.selectedDoc._height = Number(value));
+        this.selectedDoc && (this.selectedDoc._height = Math.round(value * 100) / 100);
     }
 
     @computed get hgtInput() {
         return this.inputBoxDuo(
             'hgt',
             this.shapeHgt,
-            undoable((val: string) => !isNaN(Number(val)) && (this.shapeHgt = val), 'set height'),
+            undoable((val: string) => !isNaN(Number(val)) && (this.shapeHgt = +val), 'set height'),
             'H:',
             'wid',
             this.shapeWid,
-            undoable((val: string) => !isNaN(Number(val)) && (this.shapeWid = val), 'set width'),
+            undoable((val: string) => !isNaN(Number(val)) && (this.shapeWid = +val), 'set width'),
             'W:'
         );
     }
@@ -823,11 +823,11 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         return this.inputBoxDuo(
             'Xps',
             this.shapeXps,
-            undoable((val: string) => val !== '0' && !isNaN(Number(val)) && (this.shapeXps = val), 'set x coord'),
+            undoable((val: string) => val !== '0' && !isNaN(Number(val)) && (this.shapeXps = +val), 'set x coord'),
             'X:',
             'Yps',
             this.shapeYps,
-            undoable((val: string) => val !== '0' && !isNaN(Number(val)) && (this.shapeYps = val), 'set y coord'),
+            undoable((val: string) => val !== '0' && !isNaN(Number(val)) && (this.shapeYps = +val), 'set y coord'),
             'Y:'
         );
     }
@@ -1067,11 +1067,31 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         );
     }
 
-    getNumber = (label: string, unit: string, min: number, max: number, number: number, setNumber: any) => {
+    _sliderBatch: UndoManager.Batch | undefined;
+    setFinalNumber = () => {
+        this._sliderBatch?.end();
+    };
+    getNumber = (label: string, unit: string, min: number, max: number, number: number, setNumber: any, autorange?: number, autorangeMinVal?: number) => {
         return (
-            <div>
+            <div key={label + this.selectedDoc?.title}>
                 <NumberInput formLabel={label} formLabelPlacement={'left'} type={Type.SEC} unit={unit} fillWidth color={this.color} number={number} setNumber={setNumber} min={min} max={max} />
-                <Slider multithumb={false} color={this.color} size={Size.XSMALL} min={min} max={max} unit={unit} number={number} setNumber={setNumber} fillWidth />
+                <Slider
+                    key={label}
+                    onPointerDown={e => (this._sliderBatch = UndoManager.StartBatch('slider ' + label))}
+                    multithumb={false}
+                    color={this.color}
+                    size={Size.XSMALL}
+                    min={min}
+                    max={max}
+                    autorangeMinVal={autorangeMinVal}
+                    autorange={autorange}
+                    number={number}
+                    unit={unit}
+                    decimals={1}
+                    setFinalNumber={this.setFinalNumber}
+                    setNumber={setNumber}
+                    fillWidth
+                />
             </div>
         );
     };
@@ -1080,80 +1100,40 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         return (
             <div className="transform-editor">
                 {this.isInk ? this.controlPointsButton : null}
-                {this.getNumber(
-                    'Height',
-                    ' px',
-                    0,
-                    1000,
-                    Number(this.shapeHgt),
-                    undoable((val: string) => !isNaN(Number(val)) && (this.shapeHgt = val), 'set height')
-                )}
-                {this.getNumber(
-                    'Width',
-                    ' px',
-                    0,
-                    1000,
-                    Number(this.shapeWid),
-                    undoable((val: string) => !isNaN(Number(val)) && (this.shapeWid = val), 'set width')
-                )}
-                {this.getNumber(
-                    'X', //'X Coordinate',
-                    ' px',
-                    -2000,
-                    2000,
-                    Number(this.shapeXps),
-                    undoable((val: string) => !isNaN(Number(val)) && (this.shapeXps = val), 'set x coord')
-                )}
-                {this.getNumber(
-                    'Y', //'Y Coordinate',
-                    ' px',
-                    -2000,
-                    2000,
-                    Number(this.shapeYps),
-                    undoable((val: string) => !isNaN(Number(val)) && (this.shapeYps = val), 'set y coord')
-                )}
+                {this.getNumber('Width', ' px', 0, Math.max(1000, this.shapeWid), this.shapeWid, (val: number) => !isNaN(val) && (this.shapeWid = val), 1000, 1)}
+                {this.getNumber('Height', ' px', 0, Math.max(1000, this.shapeHgt), this.shapeHgt, (val: number) => !isNaN(val) && (this.shapeHgt = val), 1000, 1)}
+                {this.getNumber('X', ' px', this.shapeXps - 500, this.shapeXps + 500, this.shapeXps, (val: number) => !isNaN(val) && (this.shapeXps = val), 1000)}
+                {this.getNumber('Y', ' px', this.shapeYps - 500, this.shapeYps + 500, this.shapeYps, (val: number) => !isNaN(val) && (this.shapeYps = val), 1000)}
             </div>
         );
     }
 
     @computed get optionsSubMenu() {
         return (
-            <PropertiesSection
-                title="Options"
-                content={<PropertiesButtons />}
-                inSection={this.inOptions}
-                isOpen={this.openOptions}
-                setInSection={bool => (this.inOptions = bool)}
-                setIsOpen={bool => (this.openOptions = bool)}
-                onDoubleClick={this.CloseAll}
-            />
+            <PropertiesSection title="Options" inSection={this.inOptions} isOpen={this.openOptions} setInSection={bool => (this.inOptions = bool)} setIsOpen={bool => (this.openOptions = bool)} onDoubleClick={this.CloseAll}>
+                <PropertiesButtons />
+            </PropertiesSection>
         );
     }
 
     @computed get sharingSubMenu() {
         return (
-            <PropertiesSection
-                title="Sharing & Permissions"
-                content={
-                    <>
-                        {/* <div className="propertiesView-buttonContainer"> */}
-                        <div className="propertiesView-acls-checkbox">
-                            Layout Permissions
-                            <Checkbox color="primary" onChange={action(() => (this.layoutDocAcls = !this.layoutDocAcls))} checked={this.layoutDocAcls} />
-                        </div>
-                        {/* <Tooltip title={<><div className="dash-tooltip">{"Re-distribute sharing settings"}</div></>}>
-                        <button onPointerDown={() => SharingManager.Instance.distributeOverCollection(this.selectedDoc!)}>
-                            <FontAwesomeIcon icon="redo-alt"  size="1x" />
-                        </button>
+            <PropertiesSection title="Sharing and Permissions" isOpen={this.openSharing} setIsOpen={bool => (this.openSharing = bool)} onDoubleClick={() => this.CloseAll()}>
+                <>
+                    {/* <div className="propertiesView-buttonContainer"> */}
+                    <div className="propertiesView-acls-checkbox">
+                        Layout Permissions
+                        <Checkbox color="primary" onChange={action(() => (this.layoutDocAcls = !this.layoutDocAcls))} checked={this.layoutDocAcls} />
+                    </div>
+                    {/* <Tooltip title={<><div className="dash-tooltip">{"Re-distribute sharing settings"}</div></>}>
+                    <button onPointerDown={() => SharingManager.Instance.distributeOverCollection(this.selectedDoc!)}>
+                        <FontAwesomeIcon icon="redo-alt"  size="1x" />
+                    </button>
                     </Tooltip> */}
-                        {/* </div> */}
-                        {this.sharingTable}
-                    </>
-                }
-                isOpen={this.openSharing}
-                setIsOpen={bool => (this.openSharing = bool)}
-                onDoubleClick={() => this.CloseAll()}
-            />
+                    {/* </div> */}
+                    {this.sharingTable}
+                </>
+            </PropertiesSection>
         );
     }
 
@@ -1183,17 +1163,11 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
 
     @computed get filtersSubMenu() {
         return (
-            <PropertiesSection
-                title="Filters"
-                content={
-                    <div className="propertiesView-content filters" style={{ position: 'relative', height: 'auto' }}>
-                        <FilterPanel rootDoc={this.selectedDoc ?? Doc.ActiveDashboard!} />
-                    </div>
-                }
-                isOpen={this.openFilters}
-                setIsOpen={bool => (this.openFilters = bool)}
-                onDoubleClick={() => this.CloseAll()}
-            />
+            <PropertiesSection title="Filters" isOpen={this.openFilters} setIsOpen={bool => (this.openFilters = bool)} onDoubleClick={() => this.CloseAll()}>
+                <div className="propertiesView-content filters" style={{ position: 'relative', height: 'auto' }}>
+                    <FilterPanel rootDoc={this.selectedDoc ?? Doc.ActiveDashboard!} />
+                </div>
+            </PropertiesSection>
         );
     }
 
@@ -1202,36 +1176,46 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
 
         return (
             <>
-                <PropertiesSection title="Appearance" content={this.isInk ? this.appearanceEditor : null} isOpen={this.openAppearance} setIsOpen={bool => (this.openAppearance = bool)} onDoubleClick={() => this.CloseAll()} />
-                <PropertiesSection title="Transform" content={this.transformEditor} isOpen={this.openTransform} setIsOpen={bool => (this.openTransform = bool)} onDoubleClick={() => this.CloseAll()} />
+                <PropertiesSection title="Appearance" isOpen={this.openAppearance} setIsOpen={bool => (this.openAppearance = bool)} onDoubleClick={() => this.CloseAll()}>
+                    {this.isInk ? this.appearanceEditor : null}
+                </PropertiesSection>
+                <PropertiesSection title="Transform" isOpen={this.openTransform} setIsOpen={bool => (this.openTransform = bool)} onDoubleClick={() => this.CloseAll()}>
+                    {this.transformEditor}
+                </PropertiesSection>
             </>
         );
     }
 
     @computed get fieldsSubMenu() {
         return (
-            <PropertiesSection
-                title="Fields & Tags"
-                content={<div className="propertiesView-content fields">{Doc.noviceMode ? this.noviceFields : this.expandedField}</div>}
-                isOpen={this.openFields}
-                setIsOpen={bool => (this.openFields = bool)}
-                onDoubleClick={() => this.CloseAll()}
-            />
+            <PropertiesSection title="Fields & Tags" isOpen={this.openFields} setIsOpen={bool => (this.openFields = bool)} onDoubleClick={() => this.CloseAll()}>
+                <div className="propertiesView-content fields">{Doc.noviceMode ? this.noviceFields : this.expandedField}</div>
+            </PropertiesSection>
         );
     }
 
     @computed get contextsSubMenu() {
         return (
-            <PropertiesSection title="Other Contexts" content={this.contextCount > 0 ? this.contexts : 'There are no other contexts.'} isOpen={this.openContexts} setIsOpen={bool => (this.openContexts = bool)} onDoubleClick={() => this.CloseAll()} />
+            <PropertiesSection title="Other Contexts" isOpen={this.openContexts} setIsOpen={bool => (this.openContexts = bool)} onDoubleClick={() => this.CloseAll()}>
+                {this.contextCount > 0 ? this.contexts : 'There are no other contexts.'}
+            </PropertiesSection>
         );
     }
 
     @computed get linksSubMenu() {
-        return <PropertiesSection title="Linked To" content={this.linkCount > 0 ? this.links : 'There are no current links.'} isOpen={this.openLinks} setIsOpen={bool => (this.openLinks = bool)} onDoubleClick={this.CloseAll} />;
+        return (
+            <PropertiesSection title="Linked To" isOpen={this.openLinks} setIsOpen={bool => (this.openLinks = bool)} onDoubleClick={this.CloseAll}>
+                {this.linkCount > 0 ? this.links : 'There are no current links.'}
+            </PropertiesSection>
+        );
     }
 
     @computed get layoutSubMenu() {
-        return <PropertiesSection title="Layout" content={this.layoutPreview} isOpen={this.openLayout} setIsOpen={bool => (this.openLayout = bool)} onDoubleClick={this.CloseAll} />;
+        return (
+            <PropertiesSection title="Layout" isOpen={this.openLayout} setIsOpen={bool => (this.openLayout = bool)} onDoubleClick={this.CloseAll}>
+                {this.layoutPreview}
+            </PropertiesSection>
+        );
     }
 
     @computed get description() {
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index ae9977d7a..da93a1b13 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -764,10 +764,10 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                         !options && cm.addItem({ description: 'Options...', subitems: optionItems, icon: 'compass' });
 
                         onClicks.push({ description: this.onClickHandler ? 'Remove Click Behavior' : 'Follow Link', event: () => this.toggleFollowLink(false, false), icon: 'link' });
-                        onClicks.push({ description: 'Edit onClick Script', event: () => UndoManager.RunInBatch(() => DocUtils.makeCustomViewClicked(this.props.Document, undefined, 'onClick'), 'edit onClick'), icon: 'terminal' });
+                        !Doc.noviceMode && 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, subitems: onClicks, icon: 'mouse-pointer' });
                     } else if (LinkManager.Links(this.Document).length) {
-                        onClicks.push({ description: 'Select on Click', event: () => this.noOnClick(), icon: 'link' });
+                        onClicks.push({ description: 'Restore On Click default', event: () => this.noOnClick(), icon: 'link' });
                         onClicks.push({ description: 'Follow Link on Click', event: () => this.followLinkOnClick(), icon: 'link' });
                         !existingOnClick && cm.addItem({ description: 'OnClick...', subitems: onClicks, icon: 'mouse-pointer' });
                     }
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 6fdde4b6b..42cc14f9c 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -666,7 +666,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
             addStyleSheetRule(FormattedTextBox._userStyleSheet, 'UM-remote', { background: 'yellow' });
         }
         if (highlights.includes('My Text')) {
-            addStyleSheetRule(FormattedTextBox._userStyleSheet, 'UM-' + Doc.CurrentUserEmail.replace('.', '').replace('@', ''), { background: 'moccasin' });
+            addStyleSheetRule(FormattedTextBox._userStyleSheet, 'UM-' + Doc.CurrentUserEmail.replace(/\./g, '').replace(/@/g, ''), { background: 'moccasin' });
         }
         if (highlights.includes('Todo Items')) {
             addStyleSheetRule(FormattedTextBox._userStyleSheet, 'UT-todo', { outline: 'black solid 1px' });
@@ -862,7 +862,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
             event: () => (this.layoutDoc._layout_enableAltContentUI = !this.layoutDoc._layout_enableAltContentUI),
             icon: !this.Document._layout_enableAltContentUI ? 'eye-slash' : 'eye',
         });
-        uicontrols.push({ description: 'Show Highlights...', noexpand: true, subitems: highlighting, icon: 'hand-point-right' });
+        !Doc.noviceMode && uicontrols.push({ description: 'Show Highlights...', noexpand: true, subitems: highlighting, icon: 'hand-point-right' });
         !Doc.noviceMode &&
             uicontrols.push({
                 description: 'Broadcast Message',
@@ -2117,7 +2117,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                     onPointerDown={this.onPointerDown}
                     onDoubleClick={this.onDoubleClick}>
                     <div
-                        className={`formattedTextBox-outer`}
+                        className="formattedTextBox-outer"
                         ref={this._scrollRef}
                         style={{
                             width: this.props.dontSelectOnLoad ? '100%' : `calc(100% - ${this.layout_sidebarWidthPercent})`,
@@ -2138,9 +2138,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                         />
                     </div>
                     {this.noSidebar || this.props.dontSelectOnLoad || !this.SidebarShown || this.layout_sidebarWidthPercent === '0%' ? null : this.sidebarCollection}
-                    {this.noSidebar || this.Document._layout_noSidebar || this.props.dontSelectOnLoad || this.Document._createDocOnCR ? null : this.sidebarHandle}
+                    {this.noSidebar || this.Document._layout_noSidebar || this.props.dontSelectOnLoad || this.Document._createDocOnCR || this.layoutDoc._chromeHidden ? null : this.sidebarHandle}
                     {this.audioHandle}
-                    {this.layoutDoc._layout_enableAltContentUI ? this.overlayAlternateIcon : null}
+                    {this.layoutDoc._layout_enableAltContentUI && !this.layoutDoc._chromeHidden ? this.overlayAlternateIcon : null}
                 </div>
             </div>
         );
diff --git a/src/client/views/nodes/formattedText/marks_rts.ts b/src/client/views/nodes/formattedText/marks_rts.ts
index 7e17008bb..6f07588b3 100644
--- a/src/client/views/nodes/formattedText/marks_rts.ts
+++ b/src/client/views/nodes/formattedText/marks_rts.ts
@@ -348,7 +348,7 @@ export const marks: { [index: string]: MarkSpec } = {
         excludes: 'user_mark',
         group: 'inline',
         toDOM(node: any) {
-            const uid = node.attrs.userid.replace('.', '').replace('@', '');
+            const uid = node.attrs.userid.replace(/\./g, '').replace(/@/g, '');
             const min = Math.round(node.attrs.modified / 60);
             const hr = Math.round(min / 60);
             const day = Math.round(hr / 60 / 24);
diff --git a/src/fields/DocSymbols.ts b/src/fields/DocSymbols.ts
index bb974ee74..df74cc9fe 100644
--- a/src/fields/DocSymbols.ts
+++ b/src/fields/DocSymbols.ts
@@ -25,4 +25,4 @@ export const Initializing = Symbol('DocInitializing');
 export const ForceServerWrite = Symbol('DocForceServerWrite');
 export const CachedUpdates = Symbol('DocCachedUpdates');
 
-export const DashVersion = 'v0.5.99';
+export const DashVersion = 'v0.6.00';
-- 
cgit v1.2.3-70-g09d2


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

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

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

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


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

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

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

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

