From 3ca56576e187e2f3cc87770b0fbdf8aa6cae73f3 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 14 Apr 2021 23:12:19 -0400
Subject: fixed image templates to set/use the appropriate nativewidth/height.
 fixed carousel views and style provider to better support properties for
 components of a document view.  fixed menus to show text options when
 captions and other sub text components are focused.

---
 src/client/views/collections/TabDocView.tsx | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

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

diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index f6aecbb14..4417038fa 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -92,7 +92,8 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                 };
                 tab.element[0].style.borderTopRightRadius = "8px";
                 tab.element[0].children[1].appendChild(toggle);
-                tab._disposers.layerDisposer = reaction(() => ({ layer: tab.DashDoc.activeLayer, color: this.tabColor }),
+                tab._disposers.layerDisposer = reaction(() =>
+                    ({ layer: tab.DashDoc.activeLayer, color: this.tabColor }),
                     ({ layer, color }) => toggle.style.background = !layer ? color : "dimgrey", { fireImmediately: true });
             }
             // shifts the focus to this tab when another tab is dragged over it
-- 
cgit v1.2.3-70-g09d2


From e7f4439446200833082e23c7b6091817031235a5 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 16 Apr 2021 13:12:17 -0400
Subject: fixed so that minimaps can't appear on non freeform collections. 
 fixed multirow/col to work with templates & stopped normalizing dimensions
 (which breaks templates). added quick and dirty lightboxDocTemplate to
 display templated documents.  fixed TextDocs to work with template fields
 that just have a text string.

---
 src/client/views/LightboxView.tsx                  | 10 ++++---
 src/client/views/collections/TabDocView.tsx        | 10 ++++---
 .../CollectionMulticolumnView.tsx                  | 27 +++++++++++--------
 .../CollectionMultirowView.tsx                     | 31 +++++++++++++---------
 src/client/views/nodes/DocumentView.tsx            | 11 ++++----
 .../views/nodes/formattedText/FormattedTextBox.tsx |  6 ++---
 6 files changed, 58 insertions(+), 37 deletions(-)

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

diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx
index b26765fa7..9c03b457b 100644
--- a/src/client/views/LightboxView.tsx
+++ b/src/client/views/LightboxView.tsx
@@ -26,6 +26,8 @@ interface LightboxViewProps {
 export class LightboxView extends React.Component<LightboxViewProps> {
 
     @computed public static get LightboxDoc() { return this._doc; }
+    private static LightboxDocTemplate = () => LightboxView._layoutTemplate;
+    @observable private static _layoutTemplate: Opt<Doc>;
     @observable private static _doc: Opt<Doc>;
     @observable private static _docTarget: Opt<Doc>;
     @observable private static _docFilters: string[] = []; // filters
@@ -35,7 +37,7 @@ export class LightboxView extends React.Component<LightboxViewProps> {
     private static _future: Opt<Doc[]> = [];
     private static _docView: Opt<DocumentView>;
     static path: { doc: Opt<Doc>, target: Opt<Doc>, history: Opt<{ doc: Doc, target?: Doc }[]>, future: Opt<Doc[]>, saved: Opt<{ panX: Opt<number>, panY: Opt<number>, scale: Opt<number>, scrollTop: Opt<number> }> }[] = [];
-    @action public static SetLightboxDoc(doc: Opt<Doc>, target?: Doc, future?: Doc[]) {
+    @action public static SetLightboxDoc(doc: Opt<Doc>, target?: Doc, future?: Doc[], layoutTemplate?: Doc) {
         if (this.LightboxDoc && this.LightboxDoc !== doc && this._savedState) {
             this.LightboxDoc._panX = this._savedState.panX;
             this.LightboxDoc._panY = this._savedState.panY;
@@ -62,6 +64,7 @@ export class LightboxView extends React.Component<LightboxViewProps> {
             this._future = future.slice().sort((a, b) => NumCast(b._timecodeToShow) - NumCast(a._timecodeToShow)).sort((a, b) => DocListCast(a.links).length - DocListCast(b.links).length);
         }
         this._doc = doc;
+        this._layoutTemplate = layoutTemplate;
         this._docTarget = target || doc;
         this._tourMap = DocListCast(doc?.links).map(link => {
             const opp = LinkManager.getOppositeAnchor(link, doc!);
@@ -101,13 +104,13 @@ export class LightboxView extends React.Component<LightboxViewProps> {
             this._docFilters = (f => this._docFilters ? [this._docFilters.push(f) as any, this._docFilters][1] : [f])(`cookies:${cookie}:provide`);
         }
     }
-    public static AddDocTab = (doc: Doc, location: string) => {
+    public static AddDocTab = (doc: Doc, location: string, layoutTemplate?: Doc) => {
         SelectionManager.DeselectAll();
         return LightboxView.SetLightboxDoc(doc, undefined,
             [...DocListCast(doc[Doc.LayoutFieldKey(doc)]),
             ...DocListCast(doc[Doc.LayoutFieldKey(doc) + "-annotations"]),
             ...(LightboxView._future ?? [])
-            ].sort((a: Doc, b: Doc) => NumCast(b._timecodeToShow) - NumCast(a._timecodeToShow)));
+            ].sort((a: Doc, b: Doc) => NumCast(b._timecodeToShow) - NumCast(a._timecodeToShow)), layoutTemplate);
     }
     docFilters = () => LightboxView._docFilters || [];
     addDocTab = LightboxView.AddDocTab;
@@ -229,6 +232,7 @@ export class LightboxView extends React.Component<LightboxViewProps> {
                     })}
                         Document={LightboxView.LightboxDoc}
                         DataDoc={undefined}
+                        LayoutTemplate={LightboxView.LightboxDocTemplate}
                         addDocument={undefined}
                         fitContentsToDoc={this.fitToBox}
                         isDocumentActive={returnFalse}
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 4417038fa..983c3732f 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -9,7 +9,7 @@ import * as ReactDOM from 'react-dom';
 import { DataSym, Doc, DocListCast, DocListCastAsync, HeightSym, Opt, WidthSym } from "../../../fields/Doc";
 import { Id } from '../../../fields/FieldSymbols';
 import { FieldId } from "../../../fields/RefField";
-import { Cast, NumCast, StrCast } from "../../../fields/Types";
+import { Cast, NumCast, StrCast, BoolCast } from "../../../fields/Types";
 import { TraceMobx } from '../../../fields/util';
 import { emptyFunction, returnEmptyDoclist, returnFalse, returnTrue, setupMoveUpEvents, Utils } from "../../../Utils";
 import { DocServer } from "../../DocServer";
@@ -299,6 +299,8 @@ export class TabDocView extends React.Component<TabDocViewProps> {
     PanelHeight = () => this._panelHeight;
     miniMapColor = () => this.tabColor;
     tabView = () => this._view;
+    disableMinimap = () => !this._document || (this._document.layout !== CollectionView.LayoutString(Doc.LayoutFieldKey(this._document)) || this._document?._viewType !== CollectionViewType.Freeform);
+    hideMinimap = () => this.disableMinimap() || BoolCast(this._document?.hideMinimap);
 
     @computed get layerProvider() { return this._document && DefaultLayerProvider(this._document); }
     @computed get docView() {
@@ -330,13 +332,14 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                 bringToFront={emptyFunction}
                 pinToPres={TabDocView.PinDoc} />
                 <TabMinimapView key="minimap"
+                    hideMinimap={this.hideMinimap}
                     addDocTab={this.addDocTab}
                     PanelHeight={this.PanelHeight}
                     PanelWidth={this.PanelWidth}
                     background={this.miniMapColor}
                     document={this._document}
                     tabView={this.tabView} />
-                <Tooltip style={{ display: this._document.layout !== CollectionView.LayoutString(Doc.LayoutFieldKey(this._document)) || this._document?._viewType !== CollectionViewType.Freeform ? "none" : undefined }} key="ttip" title={<div className="dash-tooltip">{"toggle minimap"}</div>}>
+                <Tooltip style={{ display: this.disableMinimap() ? "none" : undefined }} key="ttip" title={<div className="dash-tooltip">{"toggle minimap"}</div>}>
                     <div className="miniMap-hidden" onPointerDown={e => e.stopPropagation()} onClick={action(e => { e.stopPropagation(); this._document!.hideMinimap = !this._document!.hideMinimap; })} >
                         <FontAwesomeIcon icon={"globe-asia"} size="lg" />
                     </div>
@@ -361,6 +364,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
 
 interface TabMinimapViewProps {
     document: Doc;
+    hideMinimap: () => boolean;
     tabView: () => DocumentView | undefined;
     addDocTab: (doc: Doc, where: string) => boolean;
     PanelWidth: () => number;
@@ -411,7 +415,7 @@ export class TabMinimapView extends React.Component<TabMinimapViewProps> {
         const miniLeft = 50 + (NumCast(this.props.document._panX) - this.renderBounds.cx) / this.renderBounds.dim * 100 - miniWidth / 2;
         const miniTop = 50 + (NumCast(this.props.document._panY) - this.renderBounds.cy) / this.renderBounds.dim * 100 - miniHeight / 2;
         const miniSize = this.returnMiniSize();
-        return this.props.document.hideMinimap ? (null) :
+        return this.props.hideMinimap() ? (null) :
             <div className="miniMap" style={{ width: miniSize, height: miniSize, background: this.props.background() }}>
                 <CollectionFreeFormView
                     Document={this.props.document}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index 8c5c3431b..f3a39a262 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -49,6 +49,11 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
         return this.childLayoutPairs.map(pair => pair.layout).filter(layout => StrCast(layout._dimUnit, "*") === DimUnit.Ratio);
     }
 
+    @computed
+    private get minimumDim() {
+        return Math.min(...this.ratioDefinedDocs.filter(layout => layout._dimMagnitude).map(layout => NumCast(layout._dimMagnitude)));
+    }
+
     /**
      * This loops through all childLayoutPairs and extracts the values for _dimUnit
      * and _dimMagnitude, ignoring any that are malformed. Additionally, it then
@@ -63,7 +68,7 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
         const widthSpecifiers: WidthSpecifier[] = [];
         this.childLayoutPairs.map(pair => {
             const unit = StrCast(pair.layout._dimUnit, "*");
-            const magnitude = NumCast(pair.layout._dimMagnitude, 1);
+            const magnitude = NumCast(pair.layout._dimMagnitude, this.minimumDim);
             if (unit && magnitude && magnitude > 0 && resolvedUnits.includes(unit)) {
                 (unit === DimUnit.Ratio) && (starSum += magnitude);
                 widthSpecifiers.push({ magnitude, unit });
@@ -80,15 +85,15 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
          * themselves to drift toward zero. Thus, whenever we change any of the values,
          * we normalize everything (dividing by the smallest magnitude).
          */
-        setTimeout(() => {
-            const { ratioDefinedDocs } = this;
-            if (this.childLayoutPairs.length) {
-                const minimum = Math.min(...ratioDefinedDocs.map(doc => NumCast(doc._dimMagnitude, 1)));
-                if (minimum !== 0) {
-                    ratioDefinedDocs.forEach(layout => layout._dimMagnitude = NumCast(layout._dimMagnitude, 1) / minimum, 1);
-                }
-            }
-        });
+        // setTimeout(() => {
+        //     const { ratioDefinedDocs } = this;
+        //     if (this.childLayoutPairs.length) {
+        //         const minimum = this.minimumDim;
+        //         if (minimum !== 0) {
+        //             ratioDefinedDocs.forEach(layout => layout._dimMagnitude = NumCast(layout._dimMagnitude, 1) / minimum, 1);
+        //         }
+        //     }
+        // });
 
         return { widthSpecifiers, starSum };
     }
@@ -161,7 +166,7 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
         if (columnUnitLength === undefined) {
             return 0; // we're still waiting on promises to resolve
         }
-        let width = NumCast(layout._dimMagnitude, 1);
+        let width = NumCast(layout._dimMagnitude, this.minimumDim);
         if (StrCast(layout._dimUnit, "*") === DimUnit.Ratio) {
             width *= columnUnitLength;
         }
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index 40b155c34..29cb3511a 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -49,6 +49,11 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument)
         return this.childLayoutPairs.map(pair => pair.layout).filter(layout => StrCast(layout._dimUnit, "*") === DimUnit.Ratio);
     }
 
+    @computed
+    private get minimumDim() {
+        return Math.min(...this.ratioDefinedDocs.filter(layout => layout._dimMagnitude).map(layout => NumCast(layout._dimMagnitude)));
+    }
+
     /**
      * This loops through all childLayoutPairs and extracts the values for _dimUnit
      * and _dimUnit, ignoring any that are malformed. Additionally, it then
@@ -63,7 +68,7 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument)
         const heightSpecifiers: HeightSpecifier[] = [];
         this.childLayoutPairs.map(pair => {
             const unit = StrCast(pair.layout._dimUnit, "*");
-            const magnitude = NumCast(pair.layout._dimMagnitude, 1);
+            const magnitude = NumCast(pair.layout._dimMagnitude, this.minimumDim);
             if (unit && magnitude && magnitude > 0 && resolvedUnits.includes(unit)) {
                 (unit === DimUnit.Ratio) && (starSum += magnitude);
                 heightSpecifiers.push({ magnitude, unit });
@@ -80,15 +85,15 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument)
          * themselves to drift toward zero. Thus, whenever we change any of the values,
          * we normalize everything (dividing by the smallest magnitude).
          */
-        setTimeout(() => {
-            const { ratioDefinedDocs } = this;
-            if (this.childLayoutPairs.length) {
-                const minimum = Math.min(...ratioDefinedDocs.map(layout => NumCast(layout._dimMagnitude, 1)));
-                if (minimum !== 0) {
-                    ratioDefinedDocs.forEach(layout => layout._dimMagnitude = NumCast(layout._dimMagnitude, 1) / minimum);
-                }
-            }
-        });
+        // setTimeout(() => {
+        //     const { ratioDefinedDocs } = this;
+        //     if (this.childLayoutPairs.length) {
+        //         const minimum = Math.min(...ratioDefinedDocs.map(layout => NumCast(layout._dimMagnitude, 1)));
+        //         if (minimum !== 0) {
+        //             ratioDefinedDocs.forEach(layout => layout._dimMagnitude = NumCast(layout._dimMagnitude, 1) / minimum);
+        //         }
+        //     }
+        // });
 
         return { heightSpecifiers, starSum };
     }
@@ -161,7 +166,7 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument)
         if (rowUnitLength === undefined) {
             return 0; // we're still waiting on promises to resolve
         }
-        let height = NumCast(layout._dimMagnitude, 1);
+        let height = NumCast(layout._dimMagnitude, this.minimumDim);
         if (StrCast(layout._dimUnit, "*") === DimUnit.Ratio) {
             height *= rowUnitLength;
         }
@@ -261,7 +266,9 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument)
             const height = () => this.lookupPixels(layout);
             const width = () => PanelWidth() - 2 * NumCast(Document._xMargin) - (BoolCast(Document.showWidthLabels) ? 20 : 0);
             collector.push(
-                <div className={"document-wrapper"} key={"wrapper" + i} >
+                <div className={"document-wrapper"}
+                    style={{ height: height() }}
+                    key={"wrapper" + i} >
                     {this.getDisplayDoc(layout, dxf, width, height)}
                     <HeightLabel layout={layout} collectionDoc={Document} />
                 </div>,
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 5e97b07f0..857d06ea7 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -200,7 +200,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     @computed get finalLayoutKey() { return StrCast(this.Document.layoutKey, "layout"); }
     @computed get nativeWidth() { return this.props.NativeWidth(); }
     @computed get nativeHeight() { return this.props.NativeHeight(); }
-    @computed get onClickHandler() { return this.props.onClick?.() ?? Cast(this.Document.onClick, ScriptField, Cast(this.layoutDoc.onClick, ScriptField, null)); }
+    @computed get onClickHandler() { return this.props.onClick?.() ?? Cast(this.Document.onfClick, ScriptField, Cast(this.layoutDoc.onClick, ScriptField, null)); }
     @computed get onDoubleClickHandler() { return this.props.onDoubleClick?.() ?? (Cast(this.layoutDoc.onDoubleClick, ScriptField, null) ?? this.Document.onDoubleClick); }
     @computed get onPointerDownHandler() { return this.props.onPointerDown?.() ?? ScriptCast(this.Document.onPointerDown); }
     @computed get onPointerUpHandler() { return this.props.onPointerUp?.() ?? ScriptCast(this.Document.onPointerUp); }
@@ -453,10 +453,11 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                     }, console.log);
                     UndoManager.RunInBatch(() => func().result?.select === true ? this.props.select(false) : "", "on double click");
                 } else if (!Doc.IsSystem(this.rootDoc)) {
-                    if (this.props.Document.type !== DocumentType.LABEL) {
-                        UndoManager.RunInBatch(() => this.props.addDocTab((this.rootDoc._fullScreenView as Doc) || this.rootDoc, "lightbox"), "double tap");
-                        SelectionManager.DeselectAll();
-                    }
+                    UndoManager.RunInBatch(() =>
+                        LightboxView.AddDocTab(this.rootDoc, "lightbox", this.props.LayoutTemplate?.())
+                        //this.props.addDocTab((this.rootDoc._fullScreenView as Doc) || this.rootDoc, "lightbox")
+                        , "double tap");
+                    SelectionManager.DeselectAll();
                     Doc.UnBrushDoc(this.props.Document);
                 }
             } else if (this.onClickHandler?.script && !StrCast(Doc.LayoutField(this.layoutDoc))?.includes(ScriptingBox.name)) { // bcz: hack? don't execute script if you're clicking on a scripting box itself
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index ea854ebe7..8039e777e 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -1064,8 +1064,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         });
     }
     setupEditor(config: any, fieldKey: string) {
-        const curText = Cast(this.dataDoc[this.props.fieldKey], RichTextField, null);
-        const rtfField = Cast((!curText?.Text && this.layoutDoc[this.props.fieldKey]) || this.dataDoc[fieldKey], RichTextField);
+        const curText = Cast(this.dataDoc[this.props.fieldKey], RichTextField, null) || StrCast(this.dataDoc[this.props.fieldKey]);
+        const rtfField = Cast((!curText && this.layoutDoc[this.props.fieldKey]) || this.dataDoc[fieldKey], RichTextField);
         if (this.ProseRef) {
             const self = this;
             this._editorView?.destroy();
@@ -1118,7 +1118,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                 const tr = this._editorView.state.tr.setStoredMarks(storedMarks).insertText(FormattedTextBox.SelectOnLoadChar, this._editorView.state.doc.content.size - 1, this._editorView.state.doc.content.size).setStoredMarks(storedMarks);
                 this._editorView.dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(tr.doc.content.size))));
                 FormattedTextBox.SelectOnLoadChar = "";
-            } else if (curText?.Text && !FormattedTextBox.DontSelectInitialText) {
+            } else if (curText && !FormattedTextBox.DontSelectInitialText) {
                 selectAll(this._editorView!.state, this._editorView?.dispatch);
                 this.startUndoTypingBatch();
             }
-- 
cgit v1.2.3-70-g09d2


From 8824730d44f52ad41c2687205109a271f8c63e80 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 19 Apr 2021 12:27:33 -0400
Subject: started to cleanup comic mode.

---
 src/client/views/StyleProvider.tsx                 |  1 -
 src/client/views/collections/TabDocView.tsx        |  5 +++-
 .../nodes/CollectionFreeFormDocumentView.scss      |  6 ++++
 .../views/nodes/CollectionFreeFormDocumentView.tsx | 33 +++++++++++++---------
 4 files changed, 30 insertions(+), 15 deletions(-)

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

diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index bde741959..0702f0d6b 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -101,7 +101,6 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
         case StyleProp.HeaderMargin: return ([CollectionViewType.Stacking, CollectionViewType.Masonry].includes(doc?._viewType as any) ||
             doc?.type === DocumentType.RTF) && showTitle() && !StrCast(doc?.showTitle).includes(":hover") ? 15 : 0;
         case StyleProp.BackgroundColor: {
-            if (Doc.UserDoc().renderStyle === "comic") return "transparent";
             let docColor: Opt<string> = StrCast(doc?.[fieldKey + "backgroundColor"], StrCast(doc?._backgroundColor, isCaption ? "rbga(0,0,0,0.4)" : ""));
             if (MainView.Instance.LastButton === doc) return darkScheme() ? "dimgrey" : "lightgrey";
             switch (doc?.type) {
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 983c3732f..7e2f7811e 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -350,7 +350,10 @@ export class TabDocView extends React.Component<TabDocViewProps> {
     render() {
         this.tab && CollectionDockingView.Instance.tabMap.delete(this.tab);
         return (
-            <div className="collectionDockingView-content" style={{ height: "100%", width: "100%" }} ref={ref => {
+            <div className="collectionDockingView-content" style={{
+                fontFamily: Doc.UserDoc().renderStyle === "comic" ? "Comic Sans MS" : undefined,
+                height: "100%", width: "100%"
+            }} ref={ref => {
                 if (this._mainCont = ref) {
                     (this._mainCont as any).InitTab = (tab: any) => this.init(tab, this._document);
                     DocServer.GetRefField(this.props.documentId).then(action(doc => doc instanceof Doc && (this._document = doc) && this.tab && this.init(this.tab, this._document)));
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.scss b/src/client/views/nodes/CollectionFreeFormDocumentView.scss
index 724394025..98208c2a6 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.scss
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.scss
@@ -6,4 +6,10 @@
     top: 0;
     left: 0;
     pointer-events: none;
+    .collectionFreeFormDocumentView-comic {
+        width:100%;
+        height: 100%;
+        position: absolute;
+        top: 0;
+    }
 }
\ No newline at end of file
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 1fda4cc5e..807a61094 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -37,10 +37,14 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
     public static animFields = ["_height", "_width", "x", "y", "_scrollTop", "opacity"];  // fields that are configured to be animatable using animation frames
     @observable _animPos: number[] | undefined = undefined;
     @observable _contentView: DocumentView | undefined | null;
+    @computed get jitterRotation() {
+        const rot = this.random(-1, 1) * this.props.jitterRotation * (this.props.PanelWidth() > this.props.PanelHeight() ? 0.5 : 1);
+        return rot;
+    }
     random(min: number, max: number) { /* min should not be equal to max */ return min + ((Math.abs(this.X * this.Y) * 9301 + 49297) % 233280 / 233280) * (max - min); }
     get displayName() { return "CollectionFreeFormDocumentView(" + this.rootDoc.title + ")"; } // this makes mobx trace() statements more descriptive
     get maskCentering() { return this.props.Document.isInkMask ? InkingStroke.MaskDim / 2 : 0; }
-    get transform() { return `translate(${this.X - this.maskCentering}px, ${this.Y - this.maskCentering}px) rotate(${this.random(-1, 1) * this.props.jitterRotation}deg)`; }
+    get transform() { return `translate(${this.X - this.maskCentering}px, ${this.Y - this.maskCentering}px) rotate(${this.jitterRotation}deg)`; }
     get X() { return this.dataProvider ? this.dataProvider.x : (this.Document.x || 0); }
     get Y() { return this.dataProvider ? this.dataProvider.y : (this.Document.y || 0); }
     get ZInd() { return this.dataProvider ? this.dataProvider.zIndex : (this.Document.zIndex || 0); }
@@ -156,7 +160,9 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
     returnThis = () => this;
     render() {
         TraceMobx();
-        const backgroundColor = () => this.props.styleProvider?.(this.Document, this.props, StyleProp.BackgroundColor);
+        const pw = this.panelWidth();
+        const ph = this.panelHeight();
+        const path = `M ${pw * .5} ${ph * .05}   C ${pw * .6} ${ph * .05} ${pw * .9} 0 ${pw * .95} ${ph * .05}   C ${pw} ${ph * .1} ${pw * .95} ${ph * .2} ${pw * .95} ${ph * .25}   C ${pw * .95} ${ph * .35} ${pw} ${ph * .9} ${pw * .95} ${ph * .95}  C ${pw * .9} ${ph} ${pw * .6} ${ph * .95} ${pw * .5} ${ph * .95}   C ${pw * .3} ${ph * .95} ${pw * .1} ${ph} ${pw * .05} ${ph * .95}  C 0 ${ph * .9} ${pw * .05} ${ph * .85} ${pw * .05} ${ph * .8}   C ${pw * .05} ${ph * .75} 0 ${ph * .1} ${pw * .05} ${ph * .05}   C ${pw * .1} 0 ${pw * .25} ${ph * .05} ${pw * .5} ${ph * .05}`;
         const divProps: DocumentViewProps = {
             ...this.props,
             CollectionFreeFormDocumentView: this.returnThis,
@@ -175,18 +181,19 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
                 transition: this.props.dataTransition ? this.props.dataTransition : this.dataProvider ? this.dataProvider.transition : StrCast(this.layoutDoc.dataTransition),
                 zIndex: this.ZInd,
                 mixBlendMode: StrCast(this.layoutDoc.mixBlendMode) as any,
-                display: this.ZInd === -99 ? "none" : undefined,
+                display: this.ZInd === -99 ? "none" : undefined
             }} >
-
-            {Doc.UserDoc().renderStyle !== "comic" ? (null) :
-                <div style={{ width: "100%", height: "100%", position: "absolute" }}>
-                    <svg style={{ transform: `scale(1,${this.props.PanelHeight() / this.props.PanelWidth()})`, transformOrigin: "top left", overflow: "visible" }} viewBox="0 0 12 14">
-                        <path d="M 7 0 C 9 -1 13 1 12 4 C 11 10 13 12 10 12 C 6 12 7 13 2 12 Q -1 11 0 8 C 1 4 0 4 0 2 C 0 0 1 0 1 0 C 3 0 3 1 7 0"
-                            style={{ stroke: "black", fill: backgroundColor(), strokeWidth: 0.2 }} />
-                    </svg>
-                </div>}
-
-            <DocumentView {...divProps} ref={action((r: DocumentView | null) => this._contentView = r)} />
+            {Doc.UserDoc().renderStyle !== "comic" ? <DocumentView {...divProps} ref={action((r: DocumentView | null) => this._contentView = r)} /> :
+                <>
+                    <div key="doc" style={{ clipPath: `path('${path}')` }}>
+                        <DocumentView {...divProps} ref={action((r: DocumentView | null) => this._contentView = r)} />
+                    </div>
+                    <div key="border" className="collectionFreeFormDocumentView-comic" >
+                        <svg style={{ overflow: "visible" }} viewBox={`0 0 ${pw} ${ph}`}>
+                            <path d={path} style={{ stroke: "black", fill: "transparent", strokeWidth: 3 }} />
+                        </svg>
+                    </div>
+                </>}
         </div>;
     }
 }
-- 
cgit v1.2.3-70-g09d2

