From f5c2f5bc8710a965a0b52e2e414f62a2a459a94f Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Sun, 25 Aug 2024 04:26:12 -0400
Subject: border work

---
 src/client/views/StyleProvider.tsx | 37 +++++++++++++++++++++++++------------
 1 file changed, 25 insertions(+), 12 deletions(-)

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

diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index 8c100f238..3a48ec957 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -55,14 +55,25 @@ export function styleFromLayoutString(doc: Doc, props: FieldViewProps, scale: nu
     return style;
 }
 
-export function wavyBorderPath(pw: number, ph: number, inset: number = 0.05) {
-    return `M ${pw * 0.5} ${ph * inset}   C ${pw * 0.6} ${ph * inset} ${pw * (1 - 2 * inset)} 0 ${pw * (1 - inset)} ${ph * inset}   C ${pw} ${ph * (2 * inset)} ${pw * (1 - inset)} ${ph * 0.25} ${pw * (1 - inset)} ${ph * 0.3}   C ${
-        pw * (1 - inset)
-    } ${ph * 0.4} ${pw} ${ph * (1 - 2 * inset)} ${pw * (1 - inset)} ${ph * (1 - inset)}  C ${pw * (1 - 2 * inset)} ${ph} ${pw * 0.6} ${ph * (1 - inset)} ${pw * 0.5} ${ph * (1 - inset)}   C ${pw * 0.3} ${ph * (1 - inset)} ${pw * (2 * inset)} ${ph} ${
-        pw * inset
-    } ${ph * (1 - inset)}  C 0 ${ph * (1 - 2 * inset)} ${pw * inset} ${ph * 0.8} ${pw * inset} ${ph * 0.75}   C ${pw * inset} ${ph * 0.7} 0 ${ph * (2 * inset)} ${pw * inset} ${ph * inset}   C ${pw * (2 * inset)} 0 ${pw * 0.25} ${ph * inset} ${
-        pw * 0.5
-    } ${ph * inset}`;
+export function wavyBorderPath(doc: Doc, pw: number, ph: number, inset: number = 0) {
+    const layoutDoc = doc ? Doc.Layout(doc) : doc;
+    const width = pw * inset;
+    const height = ph * inset;
+
+    const radius = Math.min(Number(StrCast(layoutDoc._layout_borderRounding).replace('px', '')), (pw - 2 * width) / 2, (ph - 2 * height) / 2);
+
+    return `
+        M ${width + radius} ${height}
+        L ${pw - width - radius} ${height}
+        A ${radius} ${radius} 0 0 1 ${pw - width} ${height + radius}
+        L ${pw - width} ${ph - height - radius}
+        A ${radius} ${radius} 0 0 1 ${pw - width - radius} ${ph - height}
+        L ${width + radius} ${ph - height}
+        A ${radius} ${radius} 0 0 1 ${width} ${ph - height - radius}
+        L ${width} ${height + radius}
+        A ${radius} ${radius} 0 0 1 ${width + radius} ${height}
+        Z
+    `;
 }
 
 let _filterOpener: () => void;
@@ -189,10 +200,12 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps &
             const rounding = StrCast(doc?.[fieldKey + 'borderRounding'], StrCast(doc?.layout_borderRounding, doc?._type_collection === CollectionViewType.Pile ? '50%' : ''));
             return (doc?.[StrCast(doc?.layout_fieldKey)] instanceof Doc || doc?.isTemplateDoc) ? StrCast(doc._layout_borderRounding,rounding) : rounding;
         }
+        // Doc.IsComicStyle(doc) &&
+        //         renderDepth &&
+        //         !doc?.layout_isSvg && 
+        //case StyleProp.
         case StyleProp.BorderPath: {
-            const borderPath = Doc.IsComicStyle(doc) &&
-                renderDepth &&
-                !doc?.layout_isSvg && { path: wavyBorderPath(PanelWidth?.() || 0, PanelHeight?.() || 0), fill: wavyBorderPath(PanelWidth?.() || 0, PanelHeight?.() || 0, 0.08), width: 3 };
+            const borderPath = doc?.type === 'image' && { path: wavyBorderPath(doc, NumCast(doc._width), NumCast(doc._height), NumCast(layoutDoc?._layout_borderWidth)/2), fill: wavyBorderPath(doc, NumCast(doc._width), NumCast(doc._height), 0.08), width: 3 };
                 return !borderPath
                     ? null
                     : {
@@ -200,7 +213,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps &
                         jsx: (
                             <div key="border2" className="documentView-customBorder" style={{ pointerEvents: 'none' }}>
                                 <svg style={{ overflow: 'visible', height: '100%' }} viewBox={`0 0 ${PanelWidth?.()} ${PanelHeight?.()}`}>
-                                    <path d={borderPath.path} style={{ stroke: 'black', fill: 'transparent', strokeWidth: borderPath.width }} />
+                                    <path d={borderPath.path} style={{ stroke: StrCast(layoutDoc?._layout_borderColor), fill: 'transparent', strokeWidth: `${StrCast(layoutDoc?._layout_borderWidth)}px` }} />
                                 </svg>
                             </div>
                         ),
-- 
cgit v1.2.3-70-g09d2


From 42c07f05a4bb529c6f58b605cd5c98b6965afa49 Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Sun, 25 Aug 2024 14:58:05 -0400
Subject: border radius

---
 src/client/views/StyleProvider.tsx | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

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

diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index 3a48ec957..6e3eed42d 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -55,12 +55,12 @@ export function styleFromLayoutString(doc: Doc, props: FieldViewProps, scale: nu
     return style;
 }
 
-export function wavyBorderPath(doc: Doc, pw: number, ph: number, inset: number = 0) {
+export function wavyBorderPath(doc: Doc, pw: number, ph: number, rad: number = 0, inset: number = 0) {
     const layoutDoc = doc ? Doc.Layout(doc) : doc;
     const width = pw * inset;
     const height = ph * inset;
 
-    const radius = Math.min(Number(StrCast(layoutDoc._layout_borderRounding).replace('px', '')), (pw - 2 * width) / 2, (ph - 2 * height) / 2);
+    const radius = Math.min(rad, (pw - 2 * width) / 2, (ph - 2 * height) / 2);
 
     return `
         M ${width + radius} ${height}
@@ -205,7 +205,15 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps &
         //         !doc?.layout_isSvg && 
         //case StyleProp.
         case StyleProp.BorderPath: {
-            const borderPath = doc?.type === 'image' && { path: wavyBorderPath(doc, NumCast(doc._width), NumCast(doc._height), NumCast(layoutDoc?._layout_borderWidth)/2), fill: wavyBorderPath(doc, NumCast(doc._width), NumCast(doc._height), 0.08), width: 3 };
+            const docWidth = Number(doc?._width);
+            const borderWidth = Number(StrCast(layoutDoc?._layout_borderWidth));
+            const ratio = borderWidth / docWidth;
+            const borderRadius = Number(StrCast(layoutDoc?._layout_borderRounding).replace('px', ''));
+            const radiusRatio = borderRadius / docWidth;
+            const radius = radiusRatio * borderWidth;
+            console.log(borderWidth, docWidth, ratio)
+
+            const borderPath = doc?.type === 'image' && { path: wavyBorderPath(doc, NumCast(doc._width), NumCast(doc._height), radius, -ratio/2 ?? 0), fill: wavyBorderPath(doc, NumCast(doc._width), NumCast(doc._height), 0.08), width: 3 };
                 return !borderPath
                     ? null
                     : {
-- 
cgit v1.2.3-70-g09d2


From 143921c3ecee8dc0b7a91dfe725a3734d63a575e Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Sun, 25 Aug 2024 16:30:24 -0400
Subject: border

---
 src/client/views/ContextMenu.tsx        |  3 ++-
 src/client/views/StyleProvider.tsx      | 12 +++++-------
 src/client/views/nodes/DocumentView.tsx |  5 ++++-
 3 files changed, 11 insertions(+), 9 deletions(-)

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

diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx
index 9472fb95c..dca00c2bf 100644
--- a/src/client/views/ContextMenu.tsx
+++ b/src/client/views/ContextMenu.tsx
@@ -223,7 +223,8 @@ export class ContextMenu extends ObservableReactComponent<{}> {
         const layoutDoc = doc ? Doc.Layout(doc) : doc;
 
         return (
-            <div className='contextMenu-borderMenu' style={{position: 'absolute', right: `${this._pageX}`, top: `${this._pageY}`}}>
+            <div className='contextMenu-borderMenu' style={{position: 'absolute', left: this.pageX,
+            ...(this._yRelativeToTop ? { top: Math.max(0, this.pageY) } : { bottom: this.pageY }),}}>
                 <div className='top-bar'>
                     <button className='close-menu' onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, emptyFunction,
                         undoable(clickEv => {
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index 6e3eed42d..b7dbcf7a6 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -55,8 +55,7 @@ export function styleFromLayoutString(doc: Doc, props: FieldViewProps, scale: nu
     return style;
 }
 
-export function wavyBorderPath(doc: Doc, pw: number, ph: number, rad: number = 0, inset: number = 0) {
-    const layoutDoc = doc ? Doc.Layout(doc) : doc;
+export function border(doc: Doc, pw: number, ph: number, rad: number = 0, inset: number = 0) {
     const width = pw * inset;
     const height = ph * inset;
 
@@ -210,18 +209,17 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps &
             const ratio = borderWidth / docWidth;
             const borderRadius = Number(StrCast(layoutDoc?._layout_borderRounding).replace('px', ''));
             const radiusRatio = borderRadius / docWidth;
-            const radius = radiusRatio * borderWidth;
-            console.log(borderWidth, docWidth, ratio)
+            const radius = radiusRatio * ((2 * borderWidth) + docWidth);
 
-            const borderPath = doc?.type === 'image' && { path: wavyBorderPath(doc, NumCast(doc._width), NumCast(doc._height), radius, -ratio/2 ?? 0), fill: wavyBorderPath(doc, NumCast(doc._width), NumCast(doc._height), 0.08), width: 3 };
+            const borderPath = doc && border(doc, NumCast(doc._width), NumCast(doc._height), radius, -ratio/2 ?? 0);
                 return !borderPath
                     ? null
                     : {
-                        clipPath: `path('${borderPath.path}')`,
+                        clipPath: `path('${borderPath}')`,
                         jsx: (
                             <div key="border2" className="documentView-customBorder" style={{ pointerEvents: 'none' }}>
                                 <svg style={{ overflow: 'visible', height: '100%' }} viewBox={`0 0 ${PanelWidth?.()} ${PanelHeight?.()}`}>
-                                    <path d={borderPath.path} style={{ stroke: StrCast(layoutDoc?._layout_borderColor), fill: 'transparent', strokeWidth: `${StrCast(layoutDoc?._layout_borderWidth)}px` }} />
+                                    <path d={borderPath} style={{ stroke: StrCast(layoutDoc?._layout_borderColor), fill: 'transparent', strokeWidth: `${StrCast(layoutDoc?._layout_borderWidth)}px` }} />
                                 </svg>
                             </div>
                         ),
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index fe6d529ba..3c898dea2 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -547,6 +547,10 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
             return;
         }
 
+        if (!Doc.IsSystem(this.Document)) {
+            cm.addItem({ description: 'Add border', event: () => ContextMenu.Instance.setColorPickerDisplay(true), icon: 'square', colorPicker: true });
+        }
+
         const customScripts = Cast(this.Document.contextMenuScripts, listSpec(ScriptField), []);
         StrListCast(this.Document.contextMenuLabels).forEach((label, i) =>
             cm.addItem({ description: label, event: () => customScripts[i]?.script.run({ documentView: this, this: this.Document, scriptContext: this._props.scriptContext }), icon: 'sticky-note' })
@@ -634,7 +638,6 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
                     moreItems.push({ description: 'Make View of Metadata Field', event: () => Doc.MakeMetadataFieldTemplate(this.Document, this._props.TemplateDataDocument), icon: 'concierge-bell' });
                     moreItems.push({ description: `${this.Document._chromeHidden ? 'Show' : 'Hide'} Chrome`, event: () => { this.Document._chromeHidden = !this.Document._chromeHidden; }, icon: 'project-diagram' }); // prettier-ignore
                     moreItems.push({ description: 'Copy ID', event: () => ClientUtils.CopyText(Doc.globalServerPath(this.Document)), icon: 'fingerprint' });
-                    moreItems.push({ description: 'Add border', event: () => ContextMenu.Instance.setColorPickerDisplay(true), icon: 'square', colorPicker: true });
                 }
             }
 
-- 
cgit v1.2.3-70-g09d2


From f00a5326fa331859db131bb1d8988db93602830b Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Tue, 27 Aug 2024 19:16:28 -0400
Subject: maxmatching algorithm

---
 src/client/documents/Documents.ts                  |   5 +-
 src/client/views/ContextMenu.tsx                   |   9 +-
 src/client/views/StyleProvider.tsx                 |   4 +-
 .../views/nodes/DataVizBox/DocCreatorMenu.tsx      | 190 ++++++++++++++-------
 src/client/views/nodes/DocumentView.tsx            |  14 +-
 5 files changed, 139 insertions(+), 83 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index aecc79189..a4ba2978c 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -237,6 +237,9 @@ export class DocumentOptions {
     dataViz?: string;
     dataViz_savedTemplates?: LISTt;
 
+    borderWidth?: NUMt = new NumInfo('Width of user-added border', false);
+    borderColor?: STRt = new StrInfo('Color of user-added border', false);
+
     layout?: string | Doc; // default layout string or template document
     layout_isSvg?: BOOLt = new BoolInfo('whether document decorations and other selections should handle pointerEvents for svg content or use doc bounding box');
     layout_keyValue?: STRt = new StrInfo('layout definition for showing keyValue view of document', false);
@@ -256,8 +259,6 @@ export class DocumentOptions {
     layout_hideContextMenu?: BOOLt = new BoolInfo('whether the context menu can be shown');
     layout_borderRounding?: string;
     _layout_borderRounding?: STRt = new StrInfo('amount of rounding to document view corners');
-    _layout_borderWidth?: NUMt = new NumInfo('Hey now', false);
-    _layout_borderColor?: STRt = new StrInfo('No no', false);
     _layout_modificationDate?: DATEt = new DateInfo('last modification date of doc layout', false);
     _layout_nativeDimEditable?: BOOLt = new BoolInfo('native dimensions can be modified using document decoration reizers', false);
     _layout_reflowVertical?: BOOLt = new BoolInfo('permit vertical resizing with content "reflow"');
diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx
index b80d97e81..f5654446d 100644
--- a/src/client/views/ContextMenu.tsx
+++ b/src/client/views/ContextMenu.tsx
@@ -2,7 +2,7 @@
 /* eslint-disable react/jsx-props-no-spreading */
 /* eslint-disable default-param-last */
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, computed, IReactionDisposer, makeObservable, observable } from 'mobx';
+import { action, computed, IReactionDisposer, makeObservable, observable, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
 import { DivHeight, DivWidth, returnFalse, setupMoveUpEvents } from '../../ClientUtils';
@@ -222,7 +222,6 @@ export class ContextMenu extends ObservableReactComponent<{}> {
 
     get colorPicker() {
         const doc = DocumentView.Selected().lastElement().Document;
-        const layoutDoc = doc ? Doc.Layout(doc) : doc;
 
         return (
             <div className='contextMenu-borderMenu' style={{position: 'absolute', left: this.pageX,
@@ -239,15 +238,15 @@ export class ContextMenu extends ObservableReactComponent<{}> {
                 </div>
                 <SketchPicker
                 onChange={undoable(
-                    action((col: ColorResult) => layoutDoc._layout_borderColor = col.hex),
+                    action((col: ColorResult) => doc.borderColor = col.hex),
                     'set stroke color property'
                 )}
                 presetColors={[]}
-                color={StrCast(layoutDoc._layout_borderColor)}
+                color={StrCast(doc.borderColor)}
                 />
                 <div className='bottom-box'>
                     <input className='max-min-selector' defaultValue={this._widthMinMax.min} onChange={e => this._widthMinMax.max = e.target.value}/>
-                    <input className='width-selector' type="range" min={this._widthMinMax.min} max={this._widthMinMax.max} value={this._selectorWidth} id="myRange" onChange={e => {layoutDoc._layout_borderWidth = e.target.value; this._selectorWidth = Number(e.target.value); console.log(layoutDoc._layout_borderWidth)}}/>
+                    <input className='width-selector' type="range" min={this._widthMinMax.min} max={this._widthMinMax.max} value={this._selectorWidth} id="myRange" onChange={e => runInAction(() => {doc.borderWidth = e.target.value; this._selectorWidth = Number(e.target.value)})}/>
                     <input className='max-min-selector' defaultValue={this._widthMinMax.max} onChange={e => this._widthMinMax.max = e.target.value}/>
                 </div>
             </div>
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index b7dbcf7a6..3ecb101f8 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -205,7 +205,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps &
         //case StyleProp.
         case StyleProp.BorderPath: {
             const docWidth = Number(doc?._width);
-            const borderWidth = Number(StrCast(layoutDoc?._layout_borderWidth));
+            const borderWidth = Number(StrCast(doc?.borderWidth));
             const ratio = borderWidth / docWidth;
             const borderRadius = Number(StrCast(layoutDoc?._layout_borderRounding).replace('px', ''));
             const radiusRatio = borderRadius / docWidth;
@@ -219,7 +219,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps &
                         jsx: (
                             <div key="border2" className="documentView-customBorder" style={{ pointerEvents: 'none' }}>
                                 <svg style={{ overflow: 'visible', height: '100%' }} viewBox={`0 0 ${PanelWidth?.()} ${PanelHeight?.()}`}>
-                                    <path d={borderPath} style={{ stroke: StrCast(layoutDoc?._layout_borderColor), fill: 'transparent', strokeWidth: `${StrCast(layoutDoc?._layout_borderWidth)}px` }} />
+                                    <path d={borderPath} style={{ stroke: StrCast(doc?.borderColor), fill: 'transparent', strokeWidth: `${StrCast(doc?.borderWidth)}px` }} />
                                 </svg>
                             </div>
                         ),
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
index 7df445b88..ffc4dd0b1 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
@@ -419,6 +419,8 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps & Co
         // const mainCollection = this._dataViz?.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionFreeFormView;
         // mainCollection.addDocument(doc);
         //this._dataViz?.getRandomSample();
+
+        console.log(this.maxMatches(3, Array.from([[2], [1], [2]])));
     }
 
     get templatesPreviewContents(){
@@ -810,6 +812,41 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps & Co
         this.forceUpdate();
     }
 
+    findMatches = () => {
+
+    }
+
+    maxMatches = (fieldsCt: number, matches: number[][]) => {
+        const used: boolean[] = Array(fieldsCt).fill(false);
+        const mt: number[] = Array(fieldsCt).fill(-1);
+
+        const augmentingPath = (v: number): boolean => {
+            if (used[v]) return false;
+            used[v] = true;
+            for (const to of matches[v]) {
+                if (mt[to] === -1 || augmentingPath(mt[to])) {
+                    mt[to] = v;
+                    return true;
+                }
+            }
+            return false;
+        }
+    
+        for (let v = 0; v < fieldsCt; ++v) {
+            console.log(v)
+            used.fill(false);
+            augmentingPath(v);
+        }
+
+        let numMatches: number = 0;
+
+        for (let i = 0; i < fieldsCt; ++i) {
+            if (mt[i] !== -1) ++numMatches;
+        }
+
+        return numMatches;
+    }
+
     get dashboardContents(){
         return (
         <div className='docCreatorMenu-dashboard-view'>
@@ -985,26 +1022,31 @@ enum FieldSize {
     HUGE = 'huge'
 }
 
+type Field = {
+    tl: [number, number], 
+    br: [number, number], 
+    types: FieldType[], 
+    sizes?: FieldSize[], 
+    opts: FieldOpts;
+};
+
 export interface TemplateDocInfos {
     height: number;
     width: number;
-    fields: {tl: [number, number], br: [number, number], types: FieldType[], sizes?: FieldSize[]}[];
-}
-
-export interface TemplateDocField {
-    coordinates: {tl: [number, number], br: [number, number]};
-    getDoc: (parentWidth: number, parentHeight: number, title: string, content: string) => Doc;
+    fields: Field[];
 }
 
 export interface FieldOpts {
     backgroundColor?: string;
-    roundedCorners?: boolean;
-    vertCenteredText?: boolean;
-    horizCenteredText?: boolean;
-    transparency?: number;
+    color?: string;
+    cornerRounding?: number;
+    borderWidth?: number;
+    borderColor?: string;
+    contentXCentering?: 'left' | 'center' | 'right';
+    contentYCentering?: 'top' | 'center' | 'bottom';
+    opacity?: number;
     rotation?: number;
     //animation?: boolean;
-    fontColor?: string;
     fontBold?: boolean;
     fontTransform?: 'toUpper' | 'toLower';
 }
@@ -1023,7 +1065,9 @@ export class FieldFuncs {
     public static TextField = (coords: {tl: [number, number], br: [number, number]}, parentWidth: number, parentHeight: number, title: string, content: string, opts: FieldOpts) => {
         const {width, height, coord} = FieldFuncs.getDimensions(coords, parentWidth, parentHeight);
 
-        const doc = Docs.Create.TextDocument(content, {   
+        const bool = true;
+
+        const docWithBasicOpts = (Docs.Create.TextDocument)(content, {   
             _height: height, 
             _width: width, 
             title: title, 
@@ -1031,11 +1075,15 @@ export class FieldFuncs {
             y: coord.y, 
             _text_fontSize: `${height/2}` ,
             backgroundColor: opts.backgroundColor ?? '',
-            
-        
-        })
+            color: opts.color,
+            _layout_borderRounding: `${opts.cornerRounding}`,
+            borderWidth: opts.borderWidth,
+            borderColor: opts.borderColor,
+            opacity: opts.opacity,
+            _layout_centered: opts.contentXCentering === 'center' ? true : false,
+        });
 
-        return doc;
+        return docWithBasicOpts;
     }
 
     public static ImageField = (coords: {tl: [number, number], br: [number, number]}, parentWidth: number, parentHeight: number, title: string, content: string) => {
@@ -1071,70 +1119,82 @@ export class TemplateLayouts {
             tl: [-.6, -.9], 
             br: [.6, -.8], 
             types: [FieldType.TEXT],
-            sizes: [FieldSize.TINY]
+            sizes: [FieldSize.TINY],
+            opts: {
+
+            }
         }, {
             tl: [-.9, -.7], 
             br: [.9, .2], 
             types: [FieldType.TEXT, FieldType.VISUAL],
-            sizes: [FieldSize.MEDIUM, FieldSize.LARGE, FieldSize.HUGE]
+            sizes: [FieldSize.MEDIUM, FieldSize.LARGE, FieldSize.HUGE],
+            opts: {
+
+            }
         }, {
             tl: [-.6, .3], 
             br: [.6, .4], 
             types: [FieldType.TEXT],
-            sizes: [FieldSize.TINY]
+            sizes: [FieldSize.TINY],
+            opts: {
+
+            }
         }, {
             tl: [-.9, .5], 
             br: [.9, .9], 
             types: [FieldType.TEXT, FieldType.VISUAL],
-            sizes: [FieldSize.MEDIUM, FieldSize.LARGE, FieldSize.HUGE]
-        }]
-    };
+            sizes: [FieldSize.MEDIUM, FieldSize.LARGE, FieldSize.HUGE],
+            opts: {
 
-    public static FourField002: TemplateDocInfos = {
-        width: 450, 
-        height: 600, 
-        fields: [{
-            tl: [-.6, -.9], 
-            br: [.6, -.8], 
-            types: [FieldType.TEXT],
-            sizes: [FieldSize.TINY]
-        }, {
-            tl: [-.9, -.7], 
-            br: [.9, .2], 
-            types: [FieldType.TEXT, FieldType.VISUAL],
-            sizes: [FieldSize.MEDIUM, FieldSize.LARGE, FieldSize.HUGE]
-        }, {
-            tl: [-.9, .3], 
-            br: [-.05, .9], 
-            types: [FieldType.TEXT],
-            sizes: [FieldSize.TINY]
-        }, {
-            tl: [.05, .3], 
-            br: [.9, .9], 
-            types: [FieldType.TEXT, FieldType.VISUAL],
-            sizes: [FieldSize.MEDIUM, FieldSize.LARGE, FieldSize.HUGE]
+            }
         }]
     };
 
-    public static TwoFieldPlusCarousel: TemplateDocInfos = {
-        width: 500, 
-        height: 600, 
-        fields: [{
-            tl: [-.9, -.99], 
-            br: [.9, -.7], 
-            types: [FieldType.TEXT],
-            sizes: [FieldSize.TINY]
-        }, {
-            tl: [-.9, -.65], 
-            br: [.9, .35], 
-            types: [],
-            sizes: []
-        }, {
-            tl: [-.9, .4], 
-            br: [.9, .95], 
-            types: [FieldType.TEXT],
-            sizes: [FieldSize.TINY]
-        }]
-    };
+//     public static FourField002: TemplateDocInfos = {
+//         width: 450, 
+//         height: 600, 
+//         fields: [{
+//             tl: [-.6, -.9], 
+//             br: [.6, -.8], 
+//             types: [FieldType.TEXT],
+//             sizes: [FieldSize.TINY]
+//         }, {
+//             tl: [-.9, -.7], 
+//             br: [.9, .2], 
+//             types: [FieldType.TEXT, FieldType.VISUAL],
+//             sizes: [FieldSize.MEDIUM, FieldSize.LARGE, FieldSize.HUGE]
+//         }, {
+//             tl: [-.9, .3], 
+//             br: [-.05, .9], 
+//             types: [FieldType.TEXT],
+//             sizes: [FieldSize.TINY]
+//         }, {
+//             tl: [.05, .3], 
+//             br: [.9, .9], 
+//             types: [FieldType.TEXT, FieldType.VISUAL],
+//             sizes: [FieldSize.MEDIUM, FieldSize.LARGE, FieldSize.HUGE]
+//         }]
+//     };
+
+//     public static TwoFieldPlusCarousel: TemplateDocInfos = {
+//         width: 500, 
+//         height: 600, 
+//         fields: [{
+//             tl: [-.9, -.99], 
+//             br: [.9, -.7], 
+//             types: [FieldType.TEXT],
+//             sizes: [FieldSize.TINY]
+//         }, {
+//             tl: [-.9, -.65], 
+//             br: [.9, .35], 
+//             types: [],
+//             sizes: []
+//         }, {
+//             tl: [-.9, .4], 
+//             br: [.9, .95], 
+//             types: [FieldType.TEXT],
+//             sizes: [FieldSize.TINY]
+//         }]
+//     };
 
 }
\ No newline at end of file
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 3c898dea2..5af6e65de 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -948,12 +948,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
 
         return (
             // eslint-disable-next-line jsx-a11y/click-events-have-key-events
-            // <div style={{position: 'relative'}}>
-            //     <div className='docView-border-top' style={{width: `${this.layoutDoc._width}px`, height: '100px', backgroundColor: 'black'}}/>
-            //     <div className='docView-border-right' style={{position: 'absolute', right: '-10px', width: '10px', height: `${this.layoutDoc._height}px`, backgroundColor: 'black'}}/>
-            //     <div className='docView-border-left' style={{position: 'absolute', left: '-10px', width: '10px', height: `${this.layoutDoc._height}px`, backgroundColor: 'black'}}/>
-            //     <div className='docView-border-bottom' style={{position: 'absolute', bottom: '-10px', height: '100px', width: `${this.layoutDoc._width}px`, backgroundColor: 'black'}}/>
-            <div
+                <div
                     className={`${DocumentView.ROOT_DIV} docView-hack`}
                     ref={this._mainCont}
                     onContextMenu={this.onContextMenu}
@@ -969,7 +964,6 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
                     {this._componentView?.isUnstyledView?.() || this.Document.type === DocumentType.CONFIG ? renderDoc : DocumentViewInternal.AnimationEffect(renderDoc, this.Document[Animation], this.Document)}
                     {borderPath?.jsx}
                 </div>
-            // </div>
         );
     }
 
@@ -1138,7 +1132,7 @@ export class DocumentView extends DocComponent<DocumentViewProps>() {
         return Math.max(minTextScale, this._props.PanelHeight() / (this.effectiveNativeHeight || 1)); // height-limited or unscaled
     }
     @computed private get panelWidth() {
-        return this.effectiveNativeWidth ? this.effectiveNativeWidth * this.nativeScaling : this._props.PanelWidth();
+        return this.effectiveNativeWidth ? this.effectiveNativeWidth * this.nativeScaling: this._props.PanelWidth();
     }
     @computed private get panelHeight() {
         if (this.effectiveNativeHeight && (!this.layout_fitWidth || !this.layoutDoc.layout_reflowVertical)) {
@@ -1449,6 +1443,8 @@ export class DocumentView extends DocComponent<DocumentViewProps>() {
 
     render() {
         TraceMobx();
+        const borderWidth = 50/*Number(StrCast(this.layoutDoc.layout_borderWidth).replace('px', ''))*/;
+        console.log(this._props.PanelWidth(), borderWidth)
         const xshift = Math.abs(this.Xshift) <= 0.001 ? this._props.PanelWidth() : undefined;
         const yshift = Math.abs(this.Yshift) <= 0.001 ? this._props.PanelHeight() : undefined;
 
@@ -1468,7 +1464,7 @@ export class DocumentView extends DocComponent<DocumentViewProps>() {
                         style={{
                             transform: `translate(${this.centeringX}px, ${this.centeringY}px)`,
                             width: xshift ?? `${this._props.PanelWidth() - this.Xshift * 2}px`,
-                            height: this._props.forceAutoHeight ? undefined : yshift ?? (this.layout_fitWidth ? `${this.panelHeight}px` : `${(this.effectiveNativeHeight / this.effectiveNativeWidth) * this._props.PanelWidth()}px`),
+                            height: this._props.forceAutoHeight ? '1000px' : yshift ?? (this.layout_fitWidth ? `${this.panelHeight + 500}px` : `${(this.effectiveNativeHeight / this.effectiveNativeWidth) * this._props.PanelWidth() + 500}px`),
                         }}>
                         <DocumentViewInternal
                             {...this._props}
-- 
cgit v1.2.3-70-g09d2


From 85c0b1105dbdd4037872ecfc6b921551e1939eb8 Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Thu, 29 Aug 2024 04:06:15 -0400
Subject: Dataviz crash hopefully fixed; prototype func for generating
 templates; radius NaN bug handled

---
 src/client/documents/Documents.ts                  |   3 +-
 src/client/views/StyleProvider.tsx                 |   5 +
 src/client/views/nodes/DataVizBox/DataVizBox.tsx   |  18 ++-
 .../views/nodes/DataVizBox/DocCreatorMenu.tsx      | 149 +++++++++++++++------
 .../views/nodes/DataVizBox/components/TableBox.tsx |  13 +-
 src/client/views/nodes/DocumentView.tsx            |   1 -
 6 files changed, 137 insertions(+), 52 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index a4ba2978c..723f851c6 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -178,6 +178,7 @@ export class DocumentOptions {
     map_bearing?: NUMt = new NumInfo('bearing of a map view', false);
     map_style?: STRt = new StrInfo('mapbox style for a map view', false);
     identifier?: STRt = new StrInfo('documentIcon displayed for each doc as "d[x]"', false);
+    _rotation?: NUMt = new NumInfo('Amount of rotation on a document in degrees', false);
 
     date_range?: STRt = new StrInfo('date range for calendar', false);
 
@@ -237,7 +238,7 @@ export class DocumentOptions {
     dataViz?: string;
     dataViz_savedTemplates?: LISTt;
 
-    borderWidth?: NUMt = new NumInfo('Width of user-added border', false);
+    borderWidth?: STRt = new StrInfo('Width of user-added border', false);
     borderColor?: STRt = new StrInfo('Color of user-added border', false);
 
     layout?: string | Doc; // default layout string or template document
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index 3ecb101f8..bb0883cc0 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -56,11 +56,14 @@ export function styleFromLayoutString(doc: Doc, props: FieldViewProps, scale: nu
 }
 
 export function border(doc: Doc, pw: number, ph: number, rad: number = 0, inset: number = 0) {
+    if (!rad) rad = 0;
     const width = pw * inset;
     const height = ph * inset;
 
     const radius = Math.min(rad, (pw - 2 * width) / 2, (ph - 2 * height) / 2);
 
+    console.log(pw, ph, rad, inset)
+
     return `
         M ${width + radius} ${height}
         L ${pw - width - radius} ${height}
@@ -206,8 +209,10 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps &
         case StyleProp.BorderPath: {
             const docWidth = Number(doc?._width);
             const borderWidth = Number(StrCast(doc?.borderWidth));
+            //console.log(borderWidth);
             const ratio = borderWidth / docWidth;
             const borderRadius = Number(StrCast(layoutDoc?._layout_borderRounding).replace('px', ''));
+            console.log(StrCast(layoutDoc?._layout_borderRounding), borderRadius, typeof borderRadius)
             const radiusRatio = borderRadius / docWidth;
             const radius = radiusRatio * ((2 * borderWidth) + docWidth);
 
diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
index 8e9680e38..82df141fa 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
@@ -53,6 +53,7 @@ export enum DataVizView {
 
 @observer
 export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
+    private _urlError: boolean = false;
     private _mainCont: React.RefObject<HTMLDivElement> = React.createRef();
     private _marqueeref = React.createRef<MarqueeAnnotator>();
     private _annotationLayer: React.RefObject<HTMLDivElement> = React.createRef();
@@ -116,8 +117,17 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
 
     // all CSV records in the dataset (that aren't an empty row)
     @computed.struct get records() {
-        const records = DataVizBox.dataset.get(CsvCast(this.dataDoc[this.fieldKey]).url.href);
-        return records?.filter(record => Object.keys(record).some(key => record[key])) ?? [];
+        try {
+            const records = DataVizBox.dataset.get(CsvCast(this.dataDoc[this.fieldKey]).url.href);
+            this._urlError = false;
+            return records?.filter(record => Object.keys(record).some(key => record[key])) ?? [];
+        } catch (e){
+            this._urlError = true;
+            const data: { [key: string]: string; }[] = [
+                { error: "Data not found"},
+              ];          
+            return data;
+        }
     }
 
     // currently chosen visualization type: line, pie, histogram, table
@@ -133,8 +143,6 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
     }
     selectAxes = (axes: string[]) => {
         this.layoutDoc._dataViz_axes = new List<string>(axes);
-        //axes.forEach(axis => console.log(axis)) 
-        //DocCreatorMenu.Instance.generateTemplates('');
     };
     @computed.struct get titleCol() {
         return StrCast(this.layoutDoc._dataViz_titleCol);
@@ -315,7 +323,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
 
     componentDidMount() {
         this._props.setContentViewBox?.(this);
-        if (!DataVizBox.dataset.has(CsvCast(this.dataDoc[this.fieldKey]).url.href)) this.fetchData();
+        if (!this._urlError) { if (!DataVizBox.dataset.has(CsvCast(this.dataDoc[this.fieldKey]).url.href)) this.fetchData() };
         this._disposers.datavis = reaction(
             () => {
                 if (this.layoutDoc.dataViz_schemaLive === undefined) this.layoutDoc.dataViz_schemaLive = true;
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
index 43cf57167..27ffc63ef 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
@@ -404,21 +404,21 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
 
     testTemplate = () => { 
-        // const temp = TemplateLayouts.TwoFieldPlusCarousel;
-        // const title = new TemplateDocTextField({tl: temp.fields[0].tl, br: temp.fields[0].br});
-        // const title1 = new TemplateDocTextField({tl: temp.fields[0].tl, br: temp.fields[0].br});
-        // const title2 = new TemplateDocTextField({tl: temp.fields[0].tl, br: temp.fields[0].br});
-        // const title3 = new TemplateDocTextField({tl: temp.fields[0].tl, br: temp.fields[0].br});
-        // const focus = new TemplateDocCarouselField({tl: temp.fields[1].tl, br: temp.fields[1].br}, temp.width, temp.height, '', [title1, title2, title3].map(field => field.getDoc(temp.width, temp.height, 'hey now', '')));
-        // const caption = new TemplateDocTextField({tl: temp.fields[2].tl, br: temp.fields[2].br});
-        // let fields = [title, caption].map(field => field.getDoc(temp.width, temp.height, 'hey now', ''));
-        // fields = fields.concat(focus.getDoc());
-        // console.log(temp.height, temp.width)
-        // const doc = Docs.Create.StackingDocument(fields, { _height: temp.height, _width: temp.width, title: 'hey', x: 400, y: 400 });
-
-        // const mainCollection = this._dataViz?.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionFreeFormView;
-        // mainCollection.addDocument(doc);
-        //this._dataViz?.getRandomSample();
+        const temp = TemplateLayouts.FourField001;
+        const title: Doc = FieldFuncs.TextField({tl: temp.fields[0].tl, br: temp.fields[0].br}, temp.height, temp.width, 'title', 'Title', {backgroundColor: 'transparent'});
+        const image: Doc = FieldFuncs.ImageField({tl: temp.fields[1].tl, br: temp.fields[1].br}, temp.height, temp.width, 'title', '', {borderColor: '#159fe4', borderWidth: '10', cornerRounding: 10, rotation: 40});
+        const caption: Doc = FieldFuncs.TextField({tl: temp.fields[2].tl, br: temp.fields[2].br}, temp.height, temp.width, 'title', 'Caption', {backgroundColor: 'transparent'});
+        const desc: Doc = FieldFuncs.TextField({tl: temp.fields[3].tl, br: temp.fields[3].br}, temp.height, temp.width, 'title', '', {backgroundColor: 'lightblue', borderColor: '#159fe4', borderWidth: '10', cornerRounding: 10});
+
+        const doc = Docs.Create.FreeformDocument([title, image, caption, desc], { _height: temp.height, _width: temp.width, title: 'hey', x: 400, y: 400 });
+
+        const mainCollection = this._dataViz?.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionFreeFormView;
+        mainCollection.addDocument(doc);
+
+        // setTimeout(() => image.borderWidth = '10', 1000);
+        // setTimeout(() => desc.borderWidth = '10', 1000);
+
+        // this._dataViz?.getRandomSample();
 
 
         // public static FourField001: TemplateDocInfos = {
@@ -450,12 +450,12 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         //         opts: {
 
 
-        const field1: Col = {title: 'hey', type: TemplateFieldType.TEXT, size: FieldSize.HUGE, desc: ''}
-        const field2: Col = {title: 'heyo', type: TemplateFieldType.TEXT, size: FieldSize.TINY, desc: ''}
-        const field3: Col = {title: 'heya', type: TemplateFieldType.VISUAL, size: FieldSize.LARGE, desc: ''}
-        const field4: Col = {title: 'heyy', type: TemplateFieldType.TEXT, size: FieldSize.MEDIUM, desc: ''}
+        // const field1: Col = {title: 'hey', type: TemplateFieldType.TEXT, size: FieldSize.HUGE, desc: ''}
+        // const field2: Col = {title: 'heyo', type: TemplateFieldType.TEXT, size: FieldSize.TINY, desc: ''}
+        // const field3: Col = {title: 'heya', type: TemplateFieldType.VISUAL, size: FieldSize.LARGE, desc: ''}
+        // const field4: Col = {title: 'heyy', type: TemplateFieldType.TEXT, size: FieldSize.MEDIUM, desc: ''}
 
-        console.log(this.findValidTemplates([field1, field2, field3, field4], [TemplateLayouts.FourField001]));
+        // console.log(this.findValidTemplates([field1, field2, field3, field4], [TemplateLayouts.FourField001]));
     }
 
     get templatesPreviewContents(){
@@ -609,9 +609,9 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         }
     }
 
-    doc = () => {
-        return Docs.Create.FreeformDocument([], { _height: 200, _width: 200, title: 'title'});
-    }
+    // doc = () => {
+    //     return Docs.Create.FreeformDocument([], { _height: 200, _width: 200, title: 'title'});
+    // }
 
     screenToLocalTransform = () =>
     this._props
@@ -802,7 +802,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     }
 
     @action addField = () => {
-        const newFields: Col[] = this._columns.concat([{title: '', type: TemplateFieldType.TEXT, desc: '', size: FieldSize.MEDIUM}])
+        const newFields: Col[] = this._columns.concat([{title: '', type: TemplateFieldType.UNSET, desc: '', size: FieldSize.MEDIUM}])
         this._columns = newFields;
     }
 
@@ -822,9 +822,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
             if (this._columns.length === 1) {
                 this._columns = []  
             } else {
-                console.log(this._columns)
                 this._columns.splice(this._columns.indexOf(toRemove[0]), 1);
-                console.log(this._columns)
             }
         }   
     }
@@ -899,7 +897,6 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         templates.forEach(template => {
             const numFields =  template.fields.length;
             const matches = this.matchesForTemplate(template, cols);
-            console.log(matches)
             if (this.maxMatches(numFields, matches) === numFields) {
                 validTemplates.push(template.title);
             }
@@ -908,7 +905,32 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         return validTemplates;
     }
 
+    createEmptyTemplate = (template: TemplateDocInfos, assignments: {[field: number]: Col}) => {
+        const fields: Doc[] = [];
+
+        Object.entries(assignments).forEach(([f, col]) => {
+            const field: Field = template.fields[Number(f)];
+            const doc = (col.type === TemplateFieldType.VISUAL ? FieldFuncs.ImageField : FieldFuncs.TextField)({
+                tl: field.tl, 
+                br: field.br }, 
+                template.height, 
+                template.width, 
+                col.title, 
+                '', 
+                field.opts
+            );
+
+            fields.push(doc);
+        });
+
+        const renderedTemplate = Docs.Create.FreeformDocument(fields, { _height: template.height, _width: template.width, title: template.title, x: 400, y: 400 });
+
+        const mainCollection = this._dataViz?.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionFreeFormView;
+        mainCollection.addDocument(renderedTemplate);
+    }
+
     get dashboardContents(){
+
         return (
         <div className='docCreatorMenu-dashboard-view'>
             <div className='topbar'>
@@ -919,10 +941,10 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
             {this.fieldsInfos.map((field, index) => 
                 <div className='field-panel' id={`${index}`}>
                     <div className='properties-wrapper'>
-                        <input className='field-property-container' id={`${Math.random() * 100}`} defaultValue={field.title} placeholder={'Enter title'} style={{width: field.title === '' ? '30%' : ''}}/>
+                        <input className='field-property-container' id={`${Math.random() * 100}`} defaultValue={field.title} placeholder={'Enter title'}/>
                         <div className='field-type-selection-container'>
-                            {field.type ? null : <span className='placeholder'>Select media type</span>}
-                            <span className='type-display'>{field.type ? field.type === 'text' ? 'Text Field' : 'File Field' : ''}</span>
+                            {field.type === TemplateFieldType.UNSET ? <span className='placeholder'>Select media type</span> : null}
+                            <span className='type-display'>{field.type === TemplateFieldType.TEXT ? 'Text Field' : field.type === TemplateFieldType.VISUAL ? 'File Field' : ''}</span>
                             <div className='bubbles'>
                                 <input className='bubble' type="radio" name="type" onClick={() => {this.setFieldType(field, TemplateFieldType.TEXT)}}/> 
                                 <div className='text'>Text</div>
@@ -930,15 +952,13 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                                 <div className='text'>File</div>
                             </div>
                         </div>
+                        <input className='field-property-container' id={`${Math.random() * 100}`} placeholder={'Choose size'} style={{width: field.title === '' ? '30%' : ''}}/>
                     </div>
                     <textarea className='field-description-container' onChange={(e) => this._dataViz?.setFieldDesc(field.title, e.target.value)} defaultValue={field.desc === this._dataViz?.GPTSummary?.get(field.title) ? '' : field.desc } placeholder={this._dataViz?.GPTSummary?.get(field.title) ?? 'Add a description to help with template generation.'} /> 
                     <div>
                         <button className='docCreatorMenu-menu-button section-reveal-options top-right' onPointerDown={e => this.setUpButtonClick(e, () => this.removeField(field))}>
                             <FontAwesomeIcon icon='trash'/>
                         </button>
-                        {/* <button className='docCreatorMenu-menu-button section-reveal-options top-right' onPointerDown={e => this.setUpButtonClick(e, () => this.removeField(field))}>
-                            <FontAwesomeIcon icon='lightbulb'/>
-                        </button> */}
                     </div>
                 </div>
             )}
@@ -1111,7 +1131,7 @@ export interface FieldOpts {
     backgroundColor?: string;
     color?: string;
     cornerRounding?: number;
-    borderWidth?: number;
+    borderWidth?: string;
     borderColor?: string;
     contentXCentering?: 'left' | 'center' | 'right';
     contentYCentering?: 'top' | 'center' | 'bottom';
@@ -1125,8 +1145,8 @@ export interface FieldOpts {
 export class FieldFuncs {
 
     private static getDimensions = (coords: {tl: [number, number], br: [number, number]}, parentWidth: number, parentHeight: number): {width: number, height: number, coord: {x: number, y: number}} => {
-        const l = coords.tl[0] * parentWidth / 2; const t = coords.tl[1] * parentHeight / 2; //prettier-ignore
-        const r = coords.br[0] * parentWidth / 2; const b = coords.br[1] * parentHeight / 2; //prettier-ignore
+        const l = coords.tl[0] * parentHeight / 2; const t = coords.tl[1] * parentWidth / 2; //prettier-ignore
+        const r = coords.br[0] * parentHeight / 2; const b = coords.br[1] * parentWidth / 2; //prettier-ignore
         const width = r - l;
         const height = b - t;
         const coord = {x: l, y: t};
@@ -1147,17 +1167,18 @@ export class FieldFuncs {
             _text_fontSize: `${height/2}` ,
             backgroundColor: opts.backgroundColor ?? '',
             color: opts.color,
-            _layout_borderRounding: `${opts.cornerRounding}`,
-            borderWidth: opts.borderWidth,
+            _layout_borderRounding: `${opts.cornerRounding}px` ?? '0px',
             borderColor: opts.borderColor,
+            borderWidth: opts.borderWidth,
             opacity: opts.opacity,
             _layout_centered: opts.contentXCentering === 'center' ? true : false,
+            _rotation: opts.rotation,
         });
 
         return docWithBasicOpts;
     }
 
-    public static ImageField = (coords: {tl: [number, number], br: [number, number]}, parentWidth: number, parentHeight: number, title: string, content: string) => {
+    public static ImageField = (coords: {tl: [number, number], br: [number, number]}, parentWidth: number, parentHeight: number, title: string, content: string, opts: FieldOpts) => {
         const {width, height, coord} = FieldFuncs.getDimensions(coords, parentWidth, parentHeight);
 
         const doc = Docs.Create.ImageDocument(content, {   
@@ -1166,7 +1187,16 @@ export class FieldFuncs {
             title: title, 
             x: coord.x, 
             y: coord.y, 
-            _text_fontSize: `${height/2}` })
+            _text_fontSize: `${height/2}` ,
+            backgroundColor: opts.backgroundColor ?? '',
+            color: opts.color,
+            _layout_borderRounding: `${opts.cornerRounding}px` ?? '0px',
+            borderColor: opts.borderColor,
+            borderWidth: opts.borderWidth,
+            opacity: opts.opacity,
+            _layout_centered: opts.contentXCentering === 'center' ? true : false,
+            _rotation: opts.rotation,
+        });
 
         return doc;
     }
@@ -1222,6 +1252,45 @@ export class TemplateLayouts {
         }]
     };
 
+    public static FourField002: TemplateDocInfos = {
+        title: 'fourfield2',
+        width: 475, 
+        height: 870, 
+        fields: [{
+            tl: [-.95, -.83], 
+            br: [-.15, .83], 
+            types: [TemplateFieldType.VISUAL],
+            sizes: [FieldSize.MEDIUM, FieldSize.LARGE],
+            opts: {
+
+            }
+        }, {
+            tl: [-.9, -.7], 
+            br: [.9, .2], 
+            types: [TemplateFieldType.TEXT, TemplateFieldType.VISUAL],
+            sizes: [FieldSize.MEDIUM, FieldSize.LARGE, FieldSize.HUGE],
+            opts: {
+
+            }
+        }, {
+            tl: [-.6, .3], 
+            br: [.6, .4], 
+            types: [TemplateFieldType.TEXT],
+            sizes: [FieldSize.TINY],
+            opts: {
+
+            }
+        }, {
+            tl: [-.9, .5], 
+            br: [.9, .9], 
+            types: [TemplateFieldType.TEXT, TemplateFieldType.VISUAL],
+            sizes: [FieldSize.MEDIUM, FieldSize.LARGE, FieldSize.HUGE],
+            opts: {
+
+            }
+        }]
+    };
+
 //     public static FourField002: TemplateDocInfos = {
 //         width: 450, 
 //         height: 600, 
diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
index 559b8507c..6d800bc19 100644
--- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx
+++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
@@ -178,7 +178,6 @@ export class TableBox extends ObservableReactComponent<TableBoxProps> {
                 } else {
                     const newAxes = this._props.axes;
                     if (newAxes.includes(col)) newAxes.splice(newAxes.indexOf(col), 1);
-                    else if (newAxes.length > 2) newAxes[newAxes.length - 1] = col;
                     else newAxes.push(col);
                     this._props.selectAxes(newAxes);
                 }
@@ -410,11 +409,13 @@ export class TableBox extends ObservableReactComponent<TableBoxProps> {
                                                 color:
                                                     this._props.axes.slice().reverse().lastElement() === col
                                                         ? 'darkgreen'
-                                                        : this._props.axes.length > 2 && this._props.axes.lastElement() === col
+                                                        : this._props.axes.length > 3 && this._props.axes.lastElement() === col
                                                           ? 'darkred'
-                                                          : this._props.axes.lastElement() === col || (this._props.axes.length > 2 && this._props.axes[1] === col)
+                                                          : this._props.axes.length > 3 && this._props.axes[1] === col
                                                             ? 'darkblue'
-                                                            : undefined,
+                                                            : this._props.axes.lastElement() === col || (this._props.axes.length > 3 && this._props.axes[2] === col) 
+                                                              ? 'darkcyan'
+                                                              : undefined,
                                                 background: this.settingTitle
                                                     ? 'lightgrey'
                                                     : this._props.axes.slice().reverse().lastElement() === col
@@ -423,7 +424,9 @@ export class TableBox extends ObservableReactComponent<TableBoxProps> {
                                                         ? '#Fbdbdb'
                                                         : this._props.axes.lastElement() === col || (this._props.axes.length > 2 && this._props.axes[1] === col)
                                                           ? '#c6ebf7'
-                                                          : undefined,
+                                                          : this._props.axes.lastElement() === col || (this._props.axes.length > 3 && this._props.axes[2] === col) 
+                                                            ? '#c2f0f4'
+                                                            : undefined,
                                                 fontWeight: 'bolder',
                                                 border: '3px solid black',
                                             }}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 5af6e65de..79a2def87 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1444,7 +1444,6 @@ export class DocumentView extends DocComponent<DocumentViewProps>() {
     render() {
         TraceMobx();
         const borderWidth = 50/*Number(StrCast(this.layoutDoc.layout_borderWidth).replace('px', ''))*/;
-        console.log(this._props.PanelWidth(), borderWidth)
         const xshift = Math.abs(this.Xshift) <= 0.001 ? this._props.PanelWidth() : undefined;
         const yshift = Math.abs(this.Yshift) <= 0.001 ? this._props.PanelHeight() : undefined;
 
-- 
cgit v1.2.3-70-g09d2


From 1d0d2a74130ca8ca45be4f0f75f8584a60491dd9 Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Thu, 29 Aug 2024 20:04:19 -0400
Subject: one template basically loaded in

---
 src/client/views/StyleProvider.tsx                 |   3 -
 .../views/nodes/DataVizBox/DocCreatorMenu.tsx      | 458 ++++++++++++---------
 2 files changed, 266 insertions(+), 195 deletions(-)

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

diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index bb0883cc0..e7275a913 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -62,8 +62,6 @@ export function border(doc: Doc, pw: number, ph: number, rad: number = 0, inset:
 
     const radius = Math.min(rad, (pw - 2 * width) / 2, (ph - 2 * height) / 2);
 
-    console.log(pw, ph, rad, inset)
-
     return `
         M ${width + radius} ${height}
         L ${pw - width - radius} ${height}
@@ -212,7 +210,6 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps &
             //console.log(borderWidth);
             const ratio = borderWidth / docWidth;
             const borderRadius = Number(StrCast(layoutDoc?._layout_borderRounding).replace('px', ''));
-            console.log(StrCast(layoutDoc?._layout_borderRounding), borderRadius, typeof borderRadius)
             const radiusRatio = borderRadius / docWidth;
             const radius = radiusRatio * ((2 * borderWidth) + docWidth);
 
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
index 27ffc63ef..5534fced3 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
@@ -404,60 +404,180 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
 
     testTemplate = () => { 
-        const temp = TemplateLayouts.FourField001;
-        const title: Doc = FieldFuncs.TextField({tl: temp.fields[0].tl, br: temp.fields[0].br}, temp.height, temp.width, 'title', 'Title', {backgroundColor: 'transparent'});
-        const image: Doc = FieldFuncs.ImageField({tl: temp.fields[1].tl, br: temp.fields[1].br}, temp.height, temp.width, 'title', '', {borderColor: '#159fe4', borderWidth: '10', cornerRounding: 10, rotation: 40});
-        const caption: Doc = FieldFuncs.TextField({tl: temp.fields[2].tl, br: temp.fields[2].br}, temp.height, temp.width, 'title', 'Caption', {backgroundColor: 'transparent'});
-        const desc: Doc = FieldFuncs.TextField({tl: temp.fields[3].tl, br: temp.fields[3].br}, temp.height, temp.width, 'title', '', {backgroundColor: 'lightblue', borderColor: '#159fe4', borderWidth: '10', cornerRounding: 10});
+        // const temp = TemplateLayouts.FourField001;
+        // const title: Doc = FieldFuncs.TextField({tl: temp.fields[0].tl, br: temp.fields[0].br}, temp.height, temp.width, 'title', 'Title', {backgroundColor: 'transparent'});
+        // const image: Doc = FieldFuncs.ImageField({tl: temp.fields[1].tl, br: temp.fields[1].br}, temp.height, temp.width, 'title', '', {borderColor: '#159fe4', borderWidth: '10', cornerRounding: 10, rotation: 40});
+        // const caption: Doc = FieldFuncs.TextField({tl: temp.fields[2].tl, br: temp.fields[2].br}, temp.height, temp.width, 'title', 'Caption', {backgroundColor: 'transparent'});
+        // const desc: Doc = FieldFuncs.TextField({tl: temp.fields[3].tl, br: temp.fields[3].br}, temp.height, temp.width, 'title', '', {backgroundColor: 'lightblue', borderColor: '#159fe4', borderWidth: '10', cornerRounding: 10});
 
-        const doc = Docs.Create.FreeformDocument([title, image, caption, desc], { _height: temp.height, _width: temp.width, title: 'hey', x: 400, y: 400 });
+        // const doc = Docs.Create.FreeformDocument([title, image, caption, desc], { _height: temp.height, _width: temp.width, title: 'hey', x: 400, y: 400 });
 
-        const mainCollection = this._dataViz?.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionFreeFormView;
-        mainCollection.addDocument(doc);
+        // const mainCollection = this._dataViz?.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionFreeFormView;
+        // mainCollection.addDocument(doc);
+
+        const temp = TemplateLayouts.FourField002;
+
+        const img: Col = {type: TemplateFieldType.VISUAL, title: 'Image', desc: '', size: FieldSize.LARGE};
+        const capt1: Col = {type: TemplateFieldType.TEXT, title: 'Type', desc: '', size: FieldSize.TINY};
+        const capt2: Col = {type: TemplateFieldType.TEXT, title: 'Locality', desc: '', size: FieldSize.TINY};
+        const desc: Col = {type: TemplateFieldType.TEXT, title: 'Description', desc: '', size: FieldSize.LARGE};
 
-        // setTimeout(() => image.borderWidth = '10', 1000);
-        // setTimeout(() => desc.borderWidth = '10', 1000);
+        const assignments = {'0': img, '1': capt1, '2': capt2, '3': desc}
 
-        // this._dataViz?.getRandomSample();
+        this.createEmptyTemplate(temp, assignments);
+    }
 
+    @action addField = () => {
+        const newFields: Col[] = this._columns.concat([{title: '', type: TemplateFieldType.UNSET, desc: '', size: FieldSize.MEDIUM}])
+        this._columns = newFields;
+    }
+
+    @action removeField = (field: {title: string, type: string, desc: string}) => {
+        if (this._dataViz?.axes.includes(field.title)) {
+            this._dataViz.selectAxes(this._dataViz.axes.filter(col => col !== field.title));
+        } else {
+            const toRemove = this._columns.filter(f => f === field);
+            if (!toRemove) return;
+
+            if (toRemove.length > 1) {
+                while (toRemove.length > 1) {
+                    toRemove.pop();
+                }
+            }
 
-        // public static FourField001: TemplateDocInfos = {
-        //     title: 'fourfield1',
-        //     width: 450, 
-        //     height: 600, 
-        //     fields: [{
-        //         tl: [-.6, -.9], 
-        //         br: [.6, -.8], 
-        //         types: [TemplateFieldType.TEXT],
-        //         sizes: [FieldSize.TINY],
-        //         opts: {
+            if (this._columns.length === 1) {
+                this._columns = []  
+            } else {
+                this._columns.splice(this._columns.indexOf(toRemove[0]), 1);
+            }
+        }   
+    }
+
+    setFieldType = (column: Col, type: TemplateFieldType) => {
+        if (this.selectedFields.includes(column.title)) {
+            this._dataViz?.setFieldType(column.title, type);
+        } else {
+            column.type = type;
+        }
+        this.forceUpdate();
+    }
+
+    setFieldDesc = (column: Col, desc: string) => {
+        if (this.selectedFields.includes(column.title)) {
+            this._dataViz?.setFieldDesc(column.title, desc);
+        } else {
+            column.desc = desc;
+        }
+        this.forceUpdate();
+    }
+
+    matchesForTemplate = (template: TemplateDocInfos, cols: Col[]): number[][] => {
+        const colMatchesField = (col: Col, field : Field) => { return field.sizes?.includes(col.size) && field.types?.includes(col.type) };
+
+        const matches: number[][] = Array(template.fields.length).fill([]).map(() => []);
+        console.log(matches)
+        template.fields.forEach((field, i) => {
+            cols.forEach((col, v) => {
+                if (colMatchesField(col, field)) {
+                    matches[i].push(v);
+                }
+            });
+        });
+
+        return matches;
+    }
+
+    maxMatches = (fieldsCt: number, matches: number[][]) => {
+        const used: boolean[] = Array(fieldsCt).fill(false);
+        const mt: number[] = Array(fieldsCt).fill(-1);
+
+        const augmentingPath = (v: number): boolean => {
+            if (used[v]) return false;
+            used[v] = true;
+            for (const to of matches[v]) {
+                if (mt[to] === -1 || augmentingPath(mt[to])) {
+                    mt[to] = v;
+                    return true;
+                }
+            }
+            return false;
+        }
     
-        //         tl: [-.9, -.7], 
-        //         br: [.9, .2], 
-        //         types: [TemplateFieldType.TEXT, TemplateFieldType.VISUAL],
-        //         sizes: [FieldSize.MEDIUM, FieldSize.LARGE, FieldSize.HUGE],
-
-        //         tl: [-.6, .3], 
-        //         br: [.6, .4], 
-        //         types: [TemplateFieldType.TEXT],
-        //         sizes: [FieldSize.TINY],
-        //         opts: {
-
-        //         tl: [-.9, .5], 
-        //         br: [.9, .9], 
-        //         types: [TemplateFieldType.TEXT, TemplateFieldType.VISUAL],
-        //         sizes: [FieldSize.MEDIUM, FieldSize.LARGE, FieldSize.HUGE],
-        //         opts: {
-
-
-        // const field1: Col = {title: 'hey', type: TemplateFieldType.TEXT, size: FieldSize.HUGE, desc: ''}
-        // const field2: Col = {title: 'heyo', type: TemplateFieldType.TEXT, size: FieldSize.TINY, desc: ''}
-        // const field3: Col = {title: 'heya', type: TemplateFieldType.VISUAL, size: FieldSize.LARGE, desc: ''}
-        // const field4: Col = {title: 'heyy', type: TemplateFieldType.TEXT, size: FieldSize.MEDIUM, desc: ''}
-
-        // console.log(this.findValidTemplates([field1, field2, field3, field4], [TemplateLayouts.FourField001]));
+        for (let v = 0; v < fieldsCt; ++v) {
+            used.fill(false);
+            augmentingPath(v);
+        }
+
+        let count: number = 0;
+
+        for (let i = 0; i < fieldsCt; ++i) {
+            if (mt[i] !== -1) ++count;
+        }
+
+        return count;
+    }
+
+
+    findValidTemplates = (cols: Col[], templates: TemplateDocInfos[]) => {
+        const validTemplates: string[] = [];
+        templates.forEach(template => {
+            const numFields =  template.fields.length;
+            const matches = this.matchesForTemplate(template, cols);
+            if (this.maxMatches(numFields, matches) === numFields) {
+                validTemplates.push(template.title);
+            }
+        })
+
+        return validTemplates;
+    }
+
+    createEmptyTemplate = (template: TemplateDocInfos, assignments: {[field: number]: Col}) => {
+        const fields: Doc[] = [];
+
+        Object.entries(assignments).forEach(([f, col]) => {
+            const field: Field = template.fields[Number(f)];
+            console.log(field)
+            const doc = (col.type === TemplateFieldType.VISUAL ? FieldFuncs.ImageField : FieldFuncs.TextField)({
+                tl: field.tl, 
+                br: field.br }, 
+                template.height, 
+                template.width, 
+                col.title, 
+                '', 
+                field.opts
+            );
+
+            fields.push(doc);
+        });
+
+        template.decorations.forEach(dec => {
+            const doc = FieldFuncs.FreeformField({
+                tl: dec.tl, 
+                br: dec.br }, 
+                template.height, 
+                template.width, 
+                '', 
+                '', 
+                dec.opts,
+            );
+
+            fields.push(doc);
+        });
+
+        const renderedTemplate = Docs.Create.FreeformDocument(fields, { 
+            _height: template.height, 
+            _width: template.width, 
+            title: template.title, 
+            backgroundColor: template.opts.backgroundColor,
+            x: 400, 
+            y: 400 
+        });
+
+        const mainCollection = this._dataViz?.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionFreeFormView;
+        mainCollection.addDocument(renderedTemplate);
     }
 
+
     get templatesPreviewContents(){
         const renderedTemplates: Doc[] = [];
 
@@ -801,134 +921,6 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         );
     }
 
-    @action addField = () => {
-        const newFields: Col[] = this._columns.concat([{title: '', type: TemplateFieldType.UNSET, desc: '', size: FieldSize.MEDIUM}])
-        this._columns = newFields;
-    }
-
-    @action removeField = (field: {title: string, type: string, desc: string}) => {
-        if (this._dataViz?.axes.includes(field.title)) {
-            this._dataViz.selectAxes(this._dataViz.axes.filter(col => col !== field.title));
-        } else {
-            const toRemove = this._columns.filter(f => f === field);
-            if (!toRemove) return;
-
-            if (toRemove.length > 1) {
-                while (toRemove.length > 1) {
-                    toRemove.pop();
-                }
-            }
-
-            if (this._columns.length === 1) {
-                this._columns = []  
-            } else {
-                this._columns.splice(this._columns.indexOf(toRemove[0]), 1);
-            }
-        }   
-    }
-
-    setFieldType = (column: Col, type: TemplateFieldType) => {
-        if (this.selectedFields.includes(column.title)) {
-            this._dataViz?.setFieldType(column.title, type);
-        } else {
-            column.type = type;
-        }
-        this.forceUpdate();
-    }
-
-    setFieldDesc = (column: Col, desc: string) => {
-        if (this.selectedFields.includes(column.title)) {
-            this._dataViz?.setFieldDesc(column.title, desc);
-        } else {
-            column.desc = desc;
-        }
-        this.forceUpdate();
-    }
-
-    matchesForTemplate = (template: TemplateDocInfos, cols: Col[]): number[][] => {
-        const colMatchesField = (col: Col, field : Field) => { return field.sizes?.includes(col.size) && field.types.includes(col.type) };
-
-        const matches: number[][] = Array(template.fields.length).fill([]).map(() => []);
-        console.log(matches)
-        template.fields.forEach((field, i) => {
-            cols.forEach((col, v) => {
-                if (colMatchesField(col, field)) {
-                    matches[i].push(v);
-                }
-            });
-        });
-
-        return matches;
-    }
-
-    maxMatches = (fieldsCt: number, matches: number[][]) => {
-        const used: boolean[] = Array(fieldsCt).fill(false);
-        const mt: number[] = Array(fieldsCt).fill(-1);
-
-        const augmentingPath = (v: number): boolean => {
-            if (used[v]) return false;
-            used[v] = true;
-            for (const to of matches[v]) {
-                if (mt[to] === -1 || augmentingPath(mt[to])) {
-                    mt[to] = v;
-                    return true;
-                }
-            }
-            return false;
-        }
-    
-        for (let v = 0; v < fieldsCt; ++v) {
-            used.fill(false);
-            augmentingPath(v);
-        }
-
-        let count: number = 0;
-
-        for (let i = 0; i < fieldsCt; ++i) {
-            if (mt[i] !== -1) ++count;
-        }
-
-        return count;
-    }
-
-
-    findValidTemplates = (cols: Col[], templates: TemplateDocInfos[]) => {
-        const validTemplates: string[] = [];
-        templates.forEach(template => {
-            const numFields =  template.fields.length;
-            const matches = this.matchesForTemplate(template, cols);
-            if (this.maxMatches(numFields, matches) === numFields) {
-                validTemplates.push(template.title);
-            }
-        })
-
-        return validTemplates;
-    }
-
-    createEmptyTemplate = (template: TemplateDocInfos, assignments: {[field: number]: Col}) => {
-        const fields: Doc[] = [];
-
-        Object.entries(assignments).forEach(([f, col]) => {
-            const field: Field = template.fields[Number(f)];
-            const doc = (col.type === TemplateFieldType.VISUAL ? FieldFuncs.ImageField : FieldFuncs.TextField)({
-                tl: field.tl, 
-                br: field.br }, 
-                template.height, 
-                template.width, 
-                col.title, 
-                '', 
-                field.opts
-            );
-
-            fields.push(doc);
-        });
-
-        const renderedTemplate = Docs.Create.FreeformDocument(fields, { _height: template.height, _width: template.width, title: template.title, x: 400, y: 400 });
-
-        const mainCollection = this._dataViz?.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionFreeFormView;
-        mainCollection.addDocument(renderedTemplate);
-    }
-
     get dashboardContents(){
 
         return (
@@ -1115,16 +1107,24 @@ type Col = {
 type Field = {
     tl: [number, number], 
     br: [number, number], 
-    types: TemplateFieldType[], 
+    types?: TemplateFieldType[], 
     sizes?: FieldSize[], 
     opts: FieldOpts;
 };
 
+type InkDecoration = {
+
+}
+
+type TemplateDecorations = Field | InkDecoration;
+
 export interface TemplateDocInfos {
     title: string;
     height: number;
     width: number;
+    opts: TemplateOpts;
     fields: Field[];
+    decorations: Field[];
 }
 
 export interface FieldOpts {
@@ -1142,6 +1142,10 @@ export interface FieldOpts {
     fontTransform?: 'toUpper' | 'toLower';
 }
 
+interface TemplateOpts extends FieldOpts {
+
+}
+
 export class FieldFuncs {
 
     private static getDimensions = (coords: {tl: [number, number], br: [number, number]}, parentWidth: number, parentHeight: number): {width: number, height: number, coord: {x: number, y: number}} => {
@@ -1153,6 +1157,29 @@ export class FieldFuncs {
         return {width, height, coord};
     }
 
+    public static FreeformField = (coords: {tl: [number, number], br: [number, number]}, parentWidth: number, parentHeight: number, title: string, content: string, opts: FieldOpts) => {
+        const {width, height, coord} = FieldFuncs.getDimensions(coords, parentWidth, parentHeight);
+
+        const docWithBasicOpts = (Docs.Create.FreeformDocument)([], {   
+            _height: height, 
+            _width: width, 
+            title: title, 
+            x: coord.x, 
+            y: coord.y, 
+            _text_fontSize: `${height/2}` ,
+            backgroundColor: opts.backgroundColor ?? '',
+            color: opts.color,
+            _layout_borderRounding: `${opts.cornerRounding}px` ?? '0px',
+            borderColor: opts.borderColor,
+            borderWidth: opts.borderWidth,
+            opacity: opts.opacity,
+            _layout_centered: opts.contentXCentering === 'center' ? true : false,
+            _rotation: opts.rotation,
+        });
+
+        return docWithBasicOpts;
+    }
+
     public static TextField = (coords: {tl: [number, number], br: [number, number]}, parentWidth: number, parentHeight: number, title: string, content: string, opts: FieldOpts) => {
         const {width, height, coord} = FieldFuncs.getDimensions(coords, parentWidth, parentHeight);
 
@@ -1217,6 +1244,7 @@ export class TemplateLayouts {
         title: 'fourfield1',
         width: 450, 
         height: 600, 
+        opts: {},
         fields: [{
             tl: [-.6, -.9], 
             br: [.6, -.8], 
@@ -1249,46 +1277,92 @@ export class TemplateLayouts {
             opts: {
 
             }
-        }]
+        }],
+        decorations: [],
     };
 
     public static FourField002: TemplateDocInfos = {
         title: 'fourfield2',
         width: 475, 
         height: 870, 
+        opts: {
+            backgroundColor: '#242425'
+        },
         fields: [{
-            tl: [-.95, -.83], 
-            br: [-.15, .83], 
-            types: [TemplateFieldType.VISUAL],
+            tl: [-.83, -.95], 
+            br: [.83, -.2], 
+            types: [TemplateFieldType.VISUAL, TemplateFieldType.TEXT],
             sizes: [FieldSize.MEDIUM, FieldSize.LARGE],
             opts: {
-
+                borderWidth: '8',
+                borderColor: 'yellow',
             }
         }, {
-            tl: [-.9, -.7], 
-            br: [.9, .2], 
-            types: [TemplateFieldType.TEXT, TemplateFieldType.VISUAL],
-            sizes: [FieldSize.MEDIUM, FieldSize.LARGE, FieldSize.HUGE],
+            tl: [-.45, -.18], 
+            br: [.45, 0], 
+            types: [TemplateFieldType.TEXT],
+            sizes: [FieldSize.TINY, FieldSize.SMALL],
             opts: {
-
+                backgroundColor: 'transparent',
+                color: 'white'
             }
         }, {
-            tl: [-.6, .3], 
-            br: [.6, .4], 
+            tl: [-.45, 0], 
+            br: [.45, .18], 
             types: [TemplateFieldType.TEXT],
-            sizes: [FieldSize.TINY],
+            sizes: [FieldSize.TINY, FieldSize.SMALL],
             opts: {
-
+                backgroundColor: 'transparent',
+                color: 'white'
             }
         }, {
-            tl: [-.9, .5], 
-            br: [.9, .9], 
+            tl: [-.83, .2], 
+            br: [.83, .95], 
             types: [TemplateFieldType.TEXT, TemplateFieldType.VISUAL],
             sizes: [FieldSize.MEDIUM, FieldSize.LARGE, FieldSize.HUGE],
             opts: {
-
+                borderWidth: '8',
+                borderColor: 'yellow',
+            }
+        }],
+        decorations: [{
+            tl: [-.8, -.075], 
+            br: [-.525, .075], 
+            opts: {
+                backgroundColor: 'yellow',
+                rotation: 45
+            }
+        }, {
+            tl: [-.3075, -.0245], 
+            br: [-.2175, .0245], 
+            opts: {
+                backgroundColor: 'yellow',
+                rotation: 45
+            }
+        }, {
+            tl: [-.045, -.0245], 
+            br: [.045, .0245], 
+            opts: {
+                backgroundColor: 'yellow',
+                rotation: 45
+            }
+        }, {
+            tl: [.2175, -.0245], 
+            br: [.3075, .0245], 
+            opts: {
+                backgroundColor: 'yellow',
+                rotation: 45
             }
-        }]
+        }, {
+            tl: [.525, -.075], 
+            br: [.8, .075], 
+            opts: {
+                backgroundColor: 'yellow',
+                rotation: 45
+            }
+        }
+
+        ]
     };
 
 //     public static FourField002: TemplateDocInfos = {
-- 
cgit v1.2.3-70-g09d2

