From af94458be6620ae8a05730f17ee3fc4ec403cf09 Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Tue, 3 Dec 2024 19:44:25 -0500
Subject: bunch of changes related to rendering changes to template docs;
 trying to make it so docs don't need to rerender every time, and so that all
 attributes are accounted for.

---
 .../views/nodes/DataVizBox/DocCreatorMenu/Template.tsx       | 12 ++++++++++++
 1 file changed, 12 insertions(+)

(limited to 'src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx')

diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
index 31402eeeb..4680b0316 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
@@ -1,4 +1,5 @@
 
+import { makeAutoObservable } from "mobx";
 import { Doc, FieldType } from "../../../../../fields/Doc";
 import { Docs } from "../../../../documents/Documents";
 import { Col } from "./DocCreatorMenu";
@@ -6,22 +7,33 @@ import { DynamicField } from "./FieldTypes/DynamicField";
 import { Field, FieldSettings, ViewType } from "./FieldTypes/Field";
 import {  } from "./FieldTypes/FieldUtils";
 import { } from "./FieldTypes/StaticField";
+import { observer } from "mobx-react";
 
 export class Template {
 
     mainField: DynamicField;
     settings: FieldSettings;
+    
 
     constructor(templateInfo: FieldSettings) {
+        makeAutoObservable(this);
         this.mainField = this.setupMainField(templateInfo);
         this.settings = templateInfo;
+
     }
 
+
+
     get childFields(): Field[] { return this.mainField.getSubfields };
     get allFields(): Field[] { return this.mainField.getAllSubfields };
     get contentFields(): Field[] { return this.allFields.filter(field => field.getViewType === ViewType.STATIC) };
     get doc(){ return this.mainField.renderedDoc(); };
 
+    // addField = (type: FieldType, doc?: Doc): Field => {
+        
+    //     this.mainField.addField();
+    // }
+
     cloneBase = () => {
         const clone: Template = new Template(this.settings);
         clone.allFields.forEach(field => {
-- 
cgit v1.2.3-70-g09d2


From 2b9251f36be19b9fab9ce6ccc9280321c032fc0f Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Wed, 4 Dec 2024 17:49:11 -0500
Subject: stuff seems to have broken... (some changes relating to doc
 rerendering)

---
 .../DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx   |  1 -
 .../DocCreatorMenu/FieldTypes/FieldUtils.tsx       |  2 +-
 .../DocCreatorMenu/FieldTypes/StaticField.tsx      | 58 ++++++++++++++++++----
 .../nodes/DataVizBox/DocCreatorMenu/Template.tsx   |  2 -
 4 files changed, 48 insertions(+), 15 deletions(-)

(limited to 'src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx')

diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
index 5ff809170..d45e11f95 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
@@ -589,7 +589,6 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                             const col = this.getColByTitle(colTitle);
                             if (!this._userCreatedFields.includes(col)){ // do the following for any fields not added by the user; will change in the future, for now only GPT content works with user-added fields
                                 const field = template.getFieldByID(Number(fieldID));
-                                //console.log(field);
                                 field.setContent(col.defaultContent ?? '', col.type === TemplateFieldType.VISUAL ? FieldContentType.IMAGE : FieldContentType.STRING);
                                 field.setTitle(col.title);
                             } else {
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
index 9ae04d086..507790977 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
@@ -34,7 +34,7 @@ export class FieldUtils {
         doc._height = oldDoc ? oldDoc.height : parentDimensions.height;
         doc._width = oldDoc ? oldDoc.width : parentDimensions.width;
         doc.backgroundColor = oldDoc ? oldDoc.backgroundColor : opts.backgroundColor ?? '';
-        doc._layout_borderRounding = !opts._layout_borderRounding ? '0px' : ScriptField.MakeFunction(`${opts._layout_borderRounding} * this.width + 'px'`);
+        //doc._layout_borderRounding = !opts._layout_borderRounding ? '0px' : ScriptField.MakeFunction(`${opts._layout_borderRounding} * this.width + 'px'`);
         doc.borderColor = oldDoc ? oldDoc.borderColor : opts.borderColor;
         doc.borderWidth = oldDoc ? oldDoc.borderWidth : opts.borderWidth;
         doc.opacity = oldDoc ? oldDoc.opacity : opts.opacity;
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
index db54f1397..f5d86f56e 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
@@ -34,7 +34,7 @@ export class StaticField {
         this.dimensions = FieldUtils.getLocalDimensions({tl: settings.tl, br: settings.br}, this.parent.getDimensions);
         this.content = '';
         this.subfields = this.setupSubfields();
-        this.renderedDocument = this.setupRenderedDoc(this.contentType ?? FieldContentType.STRING);
+        this.renderedDocument = this.updateRenderedDoc();
         this.storedAttributes = new DocumentOptions();
     };
 
@@ -64,14 +64,13 @@ export class StaticField {
     setContent = (newContent: string, type?: FieldContentType) => { 
         this.content = newContent;
         if (type) this.contentType = type;
-        this.updateRenderedDoc(this.renderedDocument, true);
+        this.updateRenderedDoc(this.renderedDocument /*, true*/);
     };
     getContent() { return this.content };
 
     setTitle = (title: string) => { 
         this.title = title;
         this.renderedDocument.title = title;
-        this.updateRenderedDoc(this.renderedDocument);
     };
     getTitle = () => { return this.title };
 
@@ -110,25 +109,61 @@ export class StaticField {
         return matches;
     };
 
+    // updateRenderedDoc = (oldDoc?: Doc): Doc => {
+    //     const opts = this.settings.opts;
+
+    //     if (!this.contentType) { this.contentType = FieldContentType.STRING };
+
+    //     let doc: Doc;
+
+    //     switch (this.contentType) {
+    //         case FieldContentType.STRING:
+    //             const text = String(this.content);
+    //             doc = Docs.Create.TextDocument(text, {
+    //                 title: this.title,
+    //                 text_fontColor: oldDoc ? String(oldDoc.color) : opts.text_fontColor,
+    //                 contentBold: oldDoc ? Boolean(oldDoc.fontBold) : opts.contentBold,
+    //                 textTransform: oldDoc ? String(oldDoc.fontTransform) : opts.textTransform,
+    //                 color: oldDoc ? String(oldDoc.color) : opts.text_fontColor,
+    //                 _text_fontSize: `${FieldUtils.calculateFontSize(this.dimensions.width, this.dimensions.height, text, true)}`
+    //             });
+    //             FieldUtils.applyBasicOpts(doc, this.dimensions, this.settings, oldDoc);
+    //             break;
+    //         case FieldContentType.IMAGE:
+    //             const url = String(this.content);
+    //             doc = Docs.Create.ImageDocument(url, {
+    //                 title: this.title,
+    //                 _layout_fitWidth: false,
+    //             });
+    //             FieldUtils.applyBasicOpts(doc, this.dimensions, this.settings, oldDoc);
+    //             break;
+    //     }   
+
+    //     this.renderedDocument = doc;
+
+    //     return doc;
+    // };
+
     updateRenderedDoc = (currDoc?: Doc, forceRerender?: boolean) => {
-        const opts = this.settings.opts;
 
         if (!this.contentType) { this.contentType = FieldContentType.STRING };
 
         let doc: Doc;
 
-        if (this.shouldRerender()) {
+        if (this.shouldRerender() || forceRerender) {
             this.updateStoredAttributes(this.renderedDocument);
             switch (this.contentType) {
                 case FieldContentType.STRING:
                     const text = String(this.content);
+                    this.storedAttributes._text_fontSize = `${FieldUtils.calculateFontSize(this.dimensions.width, this.dimensions.height, this.content, true)}`
                     doc = Docs.Create.TextDocument(text, this.storedAttributes);
                     break;
                 case FieldContentType.IMAGE:
                     const url = String(this.content);
                     doc = Docs.Create.ImageDocument(url, this.storedAttributes);
                     break;
-            }   
+            } 
+            doc._layout_hideScroll = true;  
             this.renderedDocument = doc;
         } else {
             this.updateStoredAttributes(this.renderedDocument);
@@ -153,9 +188,7 @@ export class StaticField {
         );
     };
 
-    private setupRenderedDoc = (contentType: FieldContentType): Doc => {
-        const opts = this.settings.opts;
-
+    private setupRenderedDoc = (): Doc => {
         const docOptions: Record<string, any> = new DocumentOptions();
 
         docOptions.isDefaultTemplateDoc = true;
@@ -166,7 +199,7 @@ export class StaticField {
         docOptions._nativeWidth = this.dimensions.width;
         docOptions._nativeHeight = this.dimensions.height;
 
-        Object.keys(opts).forEach(([key, value]) => {
+        Object.entries(this.settings.opts).forEach(([key, value]) => {
             docOptions[key] = value;
         });
 
@@ -184,8 +217,11 @@ export class StaticField {
         }  
 
         doc._layout_hideScroll = true;
-        doc._layout_borderRounding = !opts._layout_borderRounding ? '0px' : ScriptField.MakeFunction(`${opts._layout_borderRounding} * this.width + 'px'`);
+        //doc._layout_borderRounding = !opts._layout_borderRounding ? '0px' : ScriptField.MakeFunction(`${opts._layout_borderRounding} * this.width + 'px'`);
+
+        this.renderedDocument = doc;
 
         return doc;
         }
+
 }
\ No newline at end of file
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
index 4680b0316..94ef1d212 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
@@ -147,8 +147,6 @@ export class Template {
             if (mt[i] !== -1) ++count;
         }
 
-        console.log(this.mainField.getTitle(), count)
-
         return count;
     };
 
-- 
cgit v1.2.3-70-g09d2


From 047bd02ea4f2a7f565ddfb5da9d1c0685d18e08e Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Sat, 7 Dec 2024 01:32:44 -0500
Subject: work started on field interface --> inheritcance structure

---
 .../DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx   | 15 ++--
 .../DocCreatorMenu/FieldTypes/DynamicField.tsx     | 34 +++++++-
 .../DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx | 81 +++++++++++++++----
 .../DocCreatorMenu/FieldTypes/StaticField.tsx      | 94 +++++++++++++---------
 .../nodes/DataVizBox/DocCreatorMenu/Template.tsx   | 20 ++---
 .../DataVizBox/DocCreatorMenu/TemplateManager.tsx  |  4 +
 src/fields/Doc.ts                                  |  2 +-
 7 files changed, 175 insertions(+), 75 deletions(-)

(limited to 'src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx')

diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
index d45e11f95..079d222d3 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
@@ -399,16 +399,19 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
     testTemplate = async () => {
 
+        const obj = new DocumentOptions();
+        console.log(Object.entries(obj)[1][0]);
+
         //console.log(this.templateManager.templates)
 
-        const mainCollection = this._dataViz?.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionFreeFormView;
+        // const mainCollection = this._dataViz?.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionFreeFormView;
         
-        this.templateManager.templates.forEach(template => {
-            const doc = template.mainField.renderedDoc();
-            mainCollection.addDocument(doc);
-        })
+        // this.templateManager.templates.forEach(template => {
+        //     const doc = template.mainField.renderedDoc();
+        //     mainCollection.addDocument(doc);
+        // })
 
-        this.forceUpdate();
+        // this.forceUpdate();
 
         // try {
         //     const res = await gptImageCall('Image of panda eating a cookie');
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
index c6f07d6c6..428f4a01c 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
@@ -1,12 +1,16 @@
-import { Doc } from "../../../../../../fields/Doc";
+import { makeAutoObservable, reaction } from "mobx";
+import { Doc, DocListCast } from "../../../../../../fields/Doc";
 import { Docs } from "../../../../../documents/Documents";
 import { Col } from "../DocCreatorMenu";
 import { TemplateLayouts } from "../TemplateBackend";
 import { Field, FieldContentType, FieldDimensions, FieldSettings, ViewType } from "./Field";
 import { FieldUtils } from "./FieldUtils";
 import { StaticField } from "./StaticField";
+import { IDisposer } from "mobx-utils";
+
+export class DynamicField extends Field {
+    private disposers: { [name: string]: IDisposer } = {};
 
-export class DynamicField implements Field {
     private subfields: Field[] = [];
 
     private id: number;
@@ -16,7 +20,11 @@ export class DynamicField implements Field {
     private parent: Field;
     private dimensions: FieldDimensions;
 
+    private renderedDocument: Doc;
+
     constructor(settings: FieldSettings, id: number, parent?: Field) {
+        super(settings, id);
+        makeAutoObservable(this);
         this.id = id;
         this.settings = settings;
         if (settings.title) { this.title = settings.title };
@@ -28,6 +36,13 @@ export class DynamicField implements Field {
             this.dimensions = FieldUtils.getLocalDimensions({tl: settings.tl, br: settings.br}, this.parent.getDimensions);
         }
         this.subfields = this.setupSubfields();
+
+        // this.disposers.fieldList = reaction(
+        //     () => DocListCast(this.doc[Doc.LayoutFieldKey(this.doc)]),
+        //     docs => {
+        //         this.handleFieldUpdate(docs);
+        //     }
+        // );
     }
 
     setContent = (content: string, type?: FieldContentType) => { return };
@@ -59,6 +74,21 @@ export class DynamicField implements Field {
         return this.settings.description ?? '';
     }
 
+    // dispose = () => {
+    //     Object.values(this.disposers).forEach(disposer => disposer?.());
+    // }
+
+    // handleFieldUpdate = (newDocsList: Doc[]) => {
+    //     const currRenderedDocs: Set<Doc> = new Set();
+    //     this.subfields.forEach(field => currRenderedDocs.add(field.renderedDoc()));
+    //     newDocsList.forEach(doc => {
+    //         if (!currRenderedDocs.has(doc)) {
+    //             this.addField(doc);
+    //         }
+    //     });
+    //     currRenderedDocs.forEach();
+    // }
+
     matches = (cols: Col[]): Array<number> => {
         return [];
     }
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
index 5eaa7381c..14f7cb109 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
@@ -1,23 +1,72 @@
 import { Doc } from "../../../../../../fields/Doc";
 import { Col } from "../DocCreatorMenu";
 import { TemplateFieldSize, TemplateFieldType } from "../TemplateBackend";
+import { DynamicField } from "./DynamicField";
+import { FieldUtils } from "./FieldUtils";
+import { StaticField } from "./StaticField";
+
+export abstract class Field {
+    protected subfields: Field[] = [];
+
+    protected abstract renderedDocument: Doc;
+
+    protected id: number;
+    protected settings: FieldSettings;
+    protected title: string = '';
+
+    protected abstract dimensions: FieldDimensions;
+
+    constructor(settings: FieldSettings, id: number) {
+        this.id = id;
+        this.settings = settings;
+        this.title = settings.title ?? '';
+    }
+
+    get getSubfields(): Field[] { return this.subfields ?? []; };
+    get getAllSubfields() {
+        let fields: Field[] = [];
+        this.subfields?.forEach(field => {
+            fields.push(field);
+            fields = fields.concat(field.getAllSubfields)
+        });
+        return fields;
+    };
+
+    get renderedDoc() { return this.renderedDocument };
+    get getDimensions() { return this.dimensions };
+    get getID() { return this.id };
+    get getViewType() { return this.settings.viewType };
+
+    setTitle = (title: string) => { 
+        this.title = title;
+        this.renderedDocument.title = title;
+    };
+    getTitle = () => { return this.title };
+
+    abstract setContent(content: string, type?: FieldContentType): void;
+    abstract getContent(): string;
+
+    addField = () => {};
+    removeField = () => {};
+
+    setupSubfields = (): Field[] => {
+        return this.settings.subfields?.map((fieldSettings, index) => {
+            const id = Number(`${this.id}${index}`);
+            return fieldSettings.viewType === ViewType.FREEFORM || fieldSettings.viewType === ViewType.CAROUSEL3D
+                ? new DynamicField(fieldSettings, id, this)
+                : new StaticField(fieldSettings, this, id);
+        }) || [];
+    }
+
+    applyAttributes(field: Field) {
+        field.setTitle(this.title);
+        field.updateRenderedDoc(this.renderedDoc);
+    }
+
+    abstract updateRenderedDoc(oldDoc?: Doc): void;
+
+    abstract matches(cols: Col[]): Array<number>;
 
-export interface Field {
-    getContent: () => string;
-    setContent: (content: string, type?: FieldContentType) => void;
-    getDimensions: FieldDimensions;
-    getSubfields: Field[];
-    getAllSubfields: Field[];
-    getID: number;
-    getViewType: ViewType;
-    getDescription: string;
-    getTitle: () => string;
-    setTitle: (title: string) => void;
-    setupSubfields: () => Field[];
-    applyAttributes: (field: Field) => void;
-    renderedDoc: () => Doc;
-    matches: (cols: Col[]) => number[];
-    updateRenderedDoc: (oldDoc?: Doc) => void;
 }
 
 export type FieldSettings = {
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
index f5d86f56e..88115c529 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
@@ -1,5 +1,5 @@
 import { TbHospital } from "react-icons/tb";
-import { Doc } from "../../../../../../fields/Doc";
+import { Doc, DocListCast } from "../../../../../../fields/Doc";
 import { FieldType } from "../../../../../../fields/ObjectField";
 import { Docs, DocumentOptions } from "../../../../../documents/Documents";
 import { Col } from "../DocCreatorMenu";
@@ -9,33 +9,38 @@ import { FieldUtils } from "./FieldUtils";
 import { Field, FieldContentType, FieldDimensions, FieldSettings, ViewType } from "./Field";
 import { indexOf } from "lodash";
 import { ScriptField } from "../../../../../../fields/ScriptField";
+import { StrCast } from "../../../../../../fields/Types";
+import { makeAutoObservable, reaction } from "mobx";
+import { IDisposer } from "mobx-utils";
+
+export class StaticField extends Field {
+    private disposers: { [name: string]: IDisposer } = {};
 
-export class StaticField {
     private content: string;
     private contentType: FieldContentType | undefined;
-    private subfields: Field[] = [];
-    private renderedDocument: Doc;
+    protected renderedDocument: Doc;
 
     private storedAttributes: Record<string, any>;
 
-    private id: number;
-    private title: string = '';
-
-    private settings: FieldSettings;
-
     private parent: Field;
-    private dimensions: FieldDimensions;
+    protected dimensions: FieldDimensions;
 
     constructor(settings: FieldSettings, parent: Field, id: number) {
-        this.settings = settings;
-        if (settings.title) { this.title = settings.title };
-        this.id = id;
+        super(settings, id);
+        makeAutoObservable(this);
         this.parent = parent;
         this.dimensions = FieldUtils.getLocalDimensions({tl: settings.tl, br: settings.br}, this.parent.getDimensions);
         this.content = '';
         this.subfields = this.setupSubfields();
-        this.renderedDocument = this.updateRenderedDoc();
+        this.renderedDocument = this.setupRenderedDoc();
         this.storedAttributes = new DocumentOptions();
+
+        this.disposers.fieldList = reaction(
+            () => DocListCast(this.renderedDocument[Doc.LayoutFieldKey(this.renderedDocument)]),
+            docs => {
+                this.handleFieldUpdate(docs);
+            }
+        );
     };
 
     get getSubfields(): Field[] { return this.subfields ?? []; };
@@ -49,18 +54,10 @@ export class StaticField {
         return fields;
     };
 
-    get getDimensions() { return this.dimensions };
-    get getID() { return this.id };
-    get getViewType() { return this.settings.viewType };
-
     get getDescription(): string {
         return this.settings.description ?? '';
     }
 
-    renderedDoc = () => {
-        return this.renderedDocument;
-    }
-
     setContent = (newContent: string, type?: FieldContentType) => { 
         this.content = newContent;
         if (type) this.contentType = type;
@@ -68,16 +65,9 @@ export class StaticField {
     };
     getContent() { return this.content };
 
-    setTitle = (title: string) => { 
-        this.title = title;
-        this.renderedDocument.title = title;
-    };
-    getTitle = () => { return this.title };
-
     applyAttributes = (field: Field) => { //!!! can be updated later for more robust clonign; this is all ythat's needed now
-        field.setTitle(this.title);
+        super.applyAttributes(field);
         field.setContent('', this.contentType);
-        field.updateRenderedDoc(this.renderedDoc());
     }
 
     setupSubfields = (): Field[] => {
@@ -89,6 +79,26 @@ export class StaticField {
         }) || [];
     }
 
+    dispose = () => {
+        Object.values(this.disposers).forEach(disposer => disposer?.());
+    }
+
+    handleFieldUpdate = (newDocsList: Doc[]) => {
+        const currRenderedDocs: Set<Doc> = new Set();
+        this.subfields.forEach(field => currRenderedDocs.add(field.renderedDoc));
+        newDocsList.forEach(doc => {
+            if (!currRenderedDocs.has(doc)) {
+                this.addField(doc);
+            }
+        });
+        currRenderedDocs.forEach(doc => {
+            if (!newDocsList.includes(doc)){
+                const fields = this.subfields.filter(field => field.renderedDoc === doc);
+                fields.forEach(field => this.removeField(field));
+            }
+        });
+    }
+
     matches = (cols: Col[]): number[] => {
         const colMatchesField = (col: Col) => {
             const isMatch: boolean = (
@@ -150,8 +160,16 @@ export class StaticField {
 
         let doc: Doc;
 
-        if (this.shouldRerender() || forceRerender) {
-            this.updateStoredAttributes(this.renderedDocument);
+        // if (this.shouldRerender() || forceRerender) {
+        // } else {
+        //     this.updateStoredAttributes(this.renderedDocument);
+        // }
+
+        this.updateStoredAttributes(this.renderedDocument);
+
+        let list: string[] = Object.entries(this.storedAttributes).map(([key, value]) => `${key}: ${value}`);
+        console.log(list);
+
             switch (this.contentType) {
                 case FieldContentType.STRING:
                     const text = String(this.content);
@@ -164,16 +182,20 @@ export class StaticField {
                     break;
             } 
             doc._layout_hideScroll = true;  
+
+
+            console.log(StrCast(doc.backgroundColor), StrCast(doc._rotation));
+
             this.renderedDocument = doc;
-        } else {
-            this.updateStoredAttributes(this.renderedDocument);
-        }
+
+        //this.renderedDocument = doc;
     };
 
     private updateStoredAttributes = (currDoc?: Doc) => {
         const opts = this.settings.opts;
+        console.log("num atts", Object.entries(this.storedAttributes).length);
         Object.entries(this.storedAttributes).forEach(([key, value]) => {
-            key = String(key);
+            key = String(key); 
             if (currDoc && currDoc[key] !== undefined) {
                 this.storedAttributes[key] = currDoc[key];
             } else if (opts[key as keyof typeof opts] !== undefined) {
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
index 94ef1d212..add588046 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
@@ -1,6 +1,6 @@
 
-import { makeAutoObservable } from "mobx";
-import { Doc, FieldType } from "../../../../../fields/Doc";
+import { makeAutoObservable, reaction } from "mobx";
+import { Doc, DocListCast, FieldType } from "../../../../../fields/Doc";
 import { Docs } from "../../../../documents/Documents";
 import { Col } from "./DocCreatorMenu";
 import { DynamicField } from "./FieldTypes/DynamicField";
@@ -8,32 +8,24 @@ import { Field, FieldSettings, ViewType } from "./FieldTypes/Field";
 import {  } from "./FieldTypes/FieldUtils";
 import { } from "./FieldTypes/StaticField";
 import { observer } from "mobx-react";
+import { IDisposer } from "mobx-utils";
 
 export class Template {
 
-    mainField: DynamicField;
-    settings: FieldSettings;
-    
+    private mainField: DynamicField;
+    private settings: FieldSettings;
 
     constructor(templateInfo: FieldSettings) {
         makeAutoObservable(this);
         this.mainField = this.setupMainField(templateInfo);
         this.settings = templateInfo;
-
     }
 
-
-
     get childFields(): Field[] { return this.mainField.getSubfields };
     get allFields(): Field[] { return this.mainField.getAllSubfields };
     get contentFields(): Field[] { return this.allFields.filter(field => field.getViewType === ViewType.STATIC) };
     get doc(){ return this.mainField.renderedDoc(); };
 
-    // addField = (type: FieldType, doc?: Doc): Field => {
-        
-    //     this.mainField.addField();
-    // }
-
     cloneBase = () => {
         const clone: Template = new Template(this.settings);
         clone.allFields.forEach(field => {
@@ -44,7 +36,7 @@ export class Template {
     }
 
     getRenderedDoc = () => {
-        const doc: Doc = this.mainField.renderedDoc();
+        const doc: Doc = this.doc;
         this.contentFields.forEach(field => {
             const title: string = field.getTitle();
             const val: FieldType = field.getContent() as FieldType;
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.tsx
index 95f0da43d..310b19890 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.tsx
@@ -1,3 +1,4 @@
+import { makeAutoObservable } from "mobx";
 import { Col } from "./DocCreatorMenu";
 import { FieldSettings } from "./FieldTypes/Field";
 import { Template } from "./Template";
@@ -6,8 +7,10 @@ import { TemplateLayouts } from "./TemplateBackend";
 export class TemplateManager {
 
     templates: Template[] = [];
+    //updateTrack
 
     constructor(templateSettings: FieldSettings[]) {
+        makeAutoObservable(this);
         this.templates = this.initializeTemplates(templateSettings);
     }
 
@@ -27,5 +30,6 @@ export class TemplateManager {
 
     removeTemplate = (template: Template) => {
         this.templates.splice(this.templates.indexOf(template), 1);
+        template.dispose();
     }
 }
\ No newline at end of file
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index a9bc5ee70..3f8de2988 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -576,7 +576,7 @@ export namespace Doc {
             if (!skipUndefineds || value !== undefined) {
                 // Do we want to filter out undefineds?
                 if (typeof value === 'object' && 'values' in value) {
-                    console.log(value);
+                    //console.log(value);
                 }
                 doc[key] = value;
             }
-- 
cgit v1.2.3-70-g09d2


From fe744903609e669c5f3048743ceba9268b8dfe0d Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Sat, 7 Dec 2024 19:46:07 -0500
Subject: field superclass

---
 .../DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx   | 82 ++++++++-----------
 .../DocCreatorMenu/FieldTypes/DynamicField.tsx     | 91 ++--------------------
 .../DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx | 84 +++++++++++++++++---
 .../DocCreatorMenu/FieldTypes/StaticField.tsx      | 53 -------------
 .../nodes/DataVizBox/DocCreatorMenu/Template.tsx   | 11 ++-
 .../DataVizBox/DocCreatorMenu/TemplateManager.tsx  |  2 +-
 6 files changed, 121 insertions(+), 202 deletions(-)

(limited to 'src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx')

diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
index 079d222d3..d8a71a610 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
@@ -400,7 +400,6 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     testTemplate = async () => {
 
         const obj = new DocumentOptions();
-        console.log(Object.entries(obj)[1][0]);
 
         //console.log(this.templateManager.templates)
 
@@ -545,7 +544,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     compileFieldDescriptions = (templates: Template[]): string => {
         let descriptions: string = '';
         templates.forEach(template => {
-            descriptions += `----------  NEW TEMPLATE TO INCLUDE: The title is: ${template.mainField.getTitle()}. Its fields are: `;
+            descriptions += `----------  NEW TEMPLATE TO INCLUDE: The title is: ${template.title}. Its fields are: `;
             descriptions += template.descriptionSummary;
         });
 
@@ -585,7 +584,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                 const brokenDownAssignments: [Template, { [fieldID: number]: Col }][] = [];
 
                 Object.entries(assignments).forEach(([tempTitle, assignment]) => {
-                    const template = templates.filter(template => template.mainField.getTitle() === tempTitle)[0];
+                    const template = templates.filter(template => template.title === tempTitle)[0];
                     if (!template) return;
                     const toObj = Object.entries(assignment).reduce(
                         (a, [fieldID, colTitle]) => {
@@ -707,7 +706,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
     createDocsFromTemplate = async (template: Template) => {
         const dv = this._dataViz;
-        console.log('dataviz: ', dv);
+
         if (!dv) return;
 
         this._docsRendering = true;
@@ -781,7 +780,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     @action setExpandedView = (template: Template | undefined) => {
         if (template) {
             this._currEditingTemplate = template;
-            this._expandedPreview = template.mainField.renderedDoc(); //Docs.Create.FreeformDocument([doc], { _height: NumListCast(doc._height)[0], _width: NumListCast(doc._width)[0], title: ''});
+            this._expandedPreview = template.doc; //Docs.Create.FreeformDocument([doc], { _height: NumListCast(doc._height)[0], _width: NumListCast(doc._width)[0], title: ''});
         } else {
             this._currEditingTemplate = undefined;
             this._expandedPreview = undefined;
@@ -839,6 +838,31 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
         const GPTOptions = <div></div>;
 
+        const previewDoc = (doc: Doc, template: Template) => 
+        <DocumentView
+        Document={doc}
+        isContentActive={emptyFunction} // !!! should be return false
+        addDocument={returnFalse}
+        moveDocument={returnFalse}
+        removeDocument={returnFalse}
+        PanelWidth={() => this._selectedTemplate === template ? 104 : 111}
+        PanelHeight={() => this._selectedTemplate === template ? 104 : 111}
+        ScreenToLocalTransform={() => new Transform(-this._pageX - 5,-this._pageY - 35, 1)}
+        renderDepth={1}
+        whenChildContentsActiveChanged={emptyFunction}
+        focus={emptyFunction}
+        styleProvider={DefaultStyleProvider}
+        addDocTab={this._props.addDocTab}
+        // eslint-disable-next-line no-use-before-define
+        pinToPres={() => undefined}
+        childFilters={returnEmptyFilter}
+        childFiltersByRanges={returnEmptyFilter}
+        searchFilterDocs={returnEmptyDoclist}
+        fitContentsToBox={returnFalse}
+        fitWidth={returnFalse}
+        hideDecorations={true}
+        />
+
         //<img className='docCreatorMenu-preview-image expanded' src={this._expandedPreview.icon!.url.href.replace(".png", "_o.png")} />
 
         return (
@@ -881,29 +905,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                                                 <button className="option-button right" onPointerDown={e => this.setUpButtonClick(e, () => this.addUserTemplate(template))}>
                                                     <FontAwesomeIcon icon="plus" color="white" />
                                                 </button>
-                                                <DocumentView
-                                                    Document={doc}
-                                                    isContentActive={emptyFunction} // !!! should be return false
-                                                    addDocument={returnFalse}
-                                                    moveDocument={returnFalse}
-                                                    removeDocument={returnFalse}
-                                                    PanelWidth={() => this._selectedTemplate === template ? 104 : 111}
-                                                    PanelHeight={() => this._selectedTemplate === template ? 104 : 111}
-                                                    ScreenToLocalTransform={() => new Transform(-this._pageX - 5,-this._pageY - 35, 1)}
-                                                    renderDepth={1}
-                                                    whenChildContentsActiveChanged={emptyFunction}
-                                                    focus={emptyFunction}
-                                                    styleProvider={DefaultStyleProvider}
-                                                    addDocTab={this._props.addDocTab}
-                                                    // eslint-disable-next-line no-use-before-define
-                                                    pinToPres={() => undefined}
-                                                    childFilters={returnEmptyFilter}
-                                                    childFiltersByRanges={returnEmptyFilter}
-                                                    searchFilterDocs={returnEmptyDoclist}
-                                                    fitContentsToBox={returnFalse}
-                                                    fitWidth={returnFalse}
-                                                    hideDecorations={true}
-                                                    />
+                                                {previewDoc(doc, template)}
                                             </div>
                                         ))
                                 )}
@@ -950,29 +952,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                                             <button className="option-button right" onPointerDown={e => this.setUpButtonClick(e, () => this.removeUserTemplate(template))}>
                                                 <FontAwesomeIcon icon="minus" color="white" />
                                             </button>
-                                            <DocumentView
-                                                Document={doc}
-                                                isContentActive={emptyFunction} // !!! should be return false
-                                                addDocument={returnFalse}
-                                                moveDocument={returnFalse}
-                                                removeDocument={returnFalse}
-                                                PanelWidth={() => this._selectedTemplate === template ? 104 : 111}
-                                                PanelHeight={() => this._selectedTemplate === template ? 104 : 111}
-                                                ScreenToLocalTransform={() => new Transform(-this._pageX - 5, -this._pageY - 35, 1)}
-                                                renderDepth={1}
-                                                whenChildContentsActiveChanged={emptyFunction}
-                                                focus={emptyFunction}
-                                                styleProvider={DefaultStyleProvider}
-                                                addDocTab={this._props.addDocTab}
-                                                // eslint-disable-next-line no-use-before-define
-                                                pinToPres={() => undefined}
-                                                childFilters={returnEmptyFilter}
-                                                childFiltersByRanges={returnEmptyFilter}
-                                                searchFilterDocs={returnEmptyDoclist}
-                                                fitContentsToBox={returnFalse}
-                                                fitWidth={returnFalse}
-                                                hideDecorations={true}
-                                                />
+                                            {previewDoc(doc, template)}
                                         </div>
                                     ))}
                             </div>
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
index 428f4a01c..681e1d48c 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
@@ -9,25 +9,14 @@ import { StaticField } from "./StaticField";
 import { IDisposer } from "mobx-utils";
 
 export class DynamicField extends Field {
-    private disposers: { [name: string]: IDisposer } = {};
-
-    private subfields: Field[] = [];
-
-    private id: number;
-    private settings: FieldSettings;
-    private title: string = '';
-
     private parent: Field;
-    private dimensions: FieldDimensions;
+    protected dimensions: FieldDimensions;
 
-    private renderedDocument: Doc;
+    protected renderedDocument: Doc;
 
     constructor(settings: FieldSettings, id: number, parent?: Field) {
         super(settings, id);
         makeAutoObservable(this);
-        this.id = id;
-        this.settings = settings;
-        if (settings.title) { this.title = settings.title };
         if (!parent) {
             this.parent = this;
             this.dimensions = {width: this.settings.br[0] - this.settings.tl[0], height: this.settings.br[1] - this.settings.tl[1], coord: {x: this.settings.tl[0], y: this.settings.tl[1]}};
@@ -35,7 +24,7 @@ export class DynamicField extends Field {
             this.parent = parent;
             this.dimensions = FieldUtils.getLocalDimensions({tl: settings.tl, br: settings.br}, this.parent.getDimensions);
         }
-        this.subfields = this.setupSubfields();
+        this.renderedDocument = new Doc(); //!!!
 
         // this.disposers.fieldList = reaction(
         //     () => DocListCast(this.doc[Doc.LayoutFieldKey(this.doc)]),
@@ -48,78 +37,10 @@ export class DynamicField extends Field {
     setContent = (content: string, type?: FieldContentType) => { return };
     getContent = () => { return '' };
 
-    setTitle = (title: string) => { this.title = title };
-    getTitle = () => { return this.title };
-
-    // addField = () => {
-    //     const newField: Field = new DynamicField();
-    //     //this.subfields.pu
-    // }
-
-    get getSubfields() { return this.subfields };
-    get getAllSubfields() {
-        let fields: Field[] = [];
-        this.subfields?.forEach(field => {
-            fields.push(field);
-            fields = fields.concat(field.getAllSubfields)
-        });
-        return fields;
-    };
-
-    get getDimensions() { return this.dimensions };
-    get getID() { return this.id };
-    get getViewType() { return this.settings.viewType };
-
-    get getDescription(): string {
-        return this.settings.description ?? '';
-    }
-
-    // dispose = () => {
-    //     Object.values(this.disposers).forEach(disposer => disposer?.());
-    // }
-
-    // handleFieldUpdate = (newDocsList: Doc[]) => {
-    //     const currRenderedDocs: Set<Doc> = new Set();
-    //     this.subfields.forEach(field => currRenderedDocs.add(field.renderedDoc()));
-    //     newDocsList.forEach(doc => {
-    //         if (!currRenderedDocs.has(doc)) {
-    //             this.addField(doc);
-    //         }
-    //     });
-    //     currRenderedDocs.forEach();
-    // }
-
     matches = (cols: Col[]): Array<number> => {
         return [];
     }
 
-    updateRenderedDoc = () => {
-        return new Doc();
-    }
-
-    setupSubfields = (): Field[] => {
-        const fields: Field[] = [];
-        this.settings.subfields?.forEach((fieldSettings, index) => {
-            let field: Field;
-            const type = fieldSettings.viewType;
-
-            const id = Number(String(this.id) + String(index));
-
-            if (type == ViewType.CAROUSEL3D || type === ViewType.FREEFORM) {
-                field = new DynamicField(fieldSettings, id, this); 
-            } else {  
-                field = new StaticField(fieldSettings, this, id);
-            }
-            fields.push(field);
-        });
-        return fields;
-    }
-
-    applyAttributes = (field: Field) => {
-        field.setTitle(this.title);
-        field.updateRenderedDoc(this.renderedDoc());
-    }
-
     getChildDimensions = (coords: { tl: [number, number]; br: [number, number] }): FieldDimensions => {
         const l = (coords.tl[0] * this.dimensions.height) / 2;
         const t = coords.tl[1] * this.dimensions.width / 2; //prettier-ignore
@@ -131,16 +52,16 @@ export class DynamicField extends Field {
         return { width, height, coord };
     };
 
-    renderedDoc = (): Doc => {
+    updateRenderedDoc = (): Doc => {
         switch (this.settings.viewType) {
             case ViewType.CAROUSEL3D:
-                const carouselDoc = Docs.Create.Carousel3DDocument(this.subfields.map(field => field.renderedDoc()), {
+                const carouselDoc = Docs.Create.Carousel3DDocument(this.subfields.map(field => field.renderedDoc), {
                     title: this.title,
                 });
                 FieldUtils.applyBasicOpts(carouselDoc, this.dimensions, this.settings);
                 return carouselDoc;
             case ViewType.FREEFORM:
-                const freeformDoc = Docs.Create.FreeformDocument(this.subfields.map(field => field.renderedDoc()), {
+                const freeformDoc = Docs.Create.FreeformDocument(this.subfields.map(field => field.renderedDoc), {
                     title: this.title,
                 });
                 FieldUtils.applyBasicOpts(freeformDoc, this.dimensions, this.settings);
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
index 14f7cb109..4d0aa10c8 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
@@ -1,12 +1,17 @@
-import { Doc } from "../../../../../../fields/Doc";
+import { makeAutoObservable, reaction } from "mobx";
+import { Doc, DocListCast } from "../../../../../../fields/Doc";
 import { Col } from "../DocCreatorMenu";
 import { TemplateFieldSize, TemplateFieldType } from "../TemplateBackend";
 import { DynamicField } from "./DynamicField";
 import { FieldUtils } from "./FieldUtils";
 import { StaticField } from "./StaticField";
+import { IDisposer } from "mobx-utils";
+import { DocumentType } from "../../../../../documents/DocumentTypes";
 
 export abstract class Field {
-    protected subfields: Field[] = [];
+    protected disposers: { [name: string]: IDisposer } = {};
+
+    protected subfields: Field[];
 
     protected abstract renderedDocument: Doc;
 
@@ -17,9 +22,19 @@ export abstract class Field {
     protected abstract dimensions: FieldDimensions;
 
     constructor(settings: FieldSettings, id: number) {
+        makeAutoObservable(this);
+        
         this.id = id;
         this.settings = settings;
         this.title = settings.title ?? '';
+        this.subfields = this.setupSubfields();
+
+        this.disposers.fieldList = reaction(
+            () => DocListCast(this.renderedDocument[Doc.LayoutFieldKey(this.renderedDocument)]),
+            docs => {
+                this.handleFieldUpdate(docs);
+            }
+        );
     }
 
     get getSubfields(): Field[] { return this.subfields ?? []; };
@@ -36,6 +51,7 @@ export abstract class Field {
     get getDimensions() { return this.dimensions };
     get getID() { return this.id };
     get getViewType() { return this.settings.viewType };
+    get getDescription(): string { return this.settings.description ?? '' };
 
     setTitle = (title: string) => { 
         this.title = title;
@@ -46,15 +62,41 @@ export abstract class Field {
     abstract setContent(content: string, type?: FieldContentType): void;
     abstract getContent(): string;
 
-    addField = () => {};
-    removeField = () => {};
+    addFieldFromDoc = (doc: Doc) => {
+        const settings: FieldSettings = {
+            tl: [Number(doc._x), Number(doc._y)],
+            br: [Number(doc._x) + Number(doc._width), Number(doc._y) + Number(doc._height)],
+            viewType: doc.type === DocumentType.COL ? ViewType.FREEFORM : ViewType.STATIC,
+            opts: {},
+        };
+
+        Object.getOwnPropertyNames(FieldOpts.prototype).forEach(([key, value]) => {
+            settings.opts[key as keyof FieldOpts] = StringCast(doc[key]);
+        });
+
+        const newField = this.setupField(settings, this.subfields.length)
+        this.subfields.push(newField);
+    };
+
+    addField = (type?: FieldContentType) => {
+
+    }
+
+    removeField = (field: Field) => {
+        this.subfields.splice(this.subfields.indexOf(field), 1);
+        field.dispose();
+    };
+
+    private setupField = (settings: FieldSettings, index: number): Field => { 
+        const id = Number(`${this.id}${index}`);
+        return settings.viewType === ViewType.FREEFORM || settings.viewType === ViewType.CAROUSEL3D
+        ? new DynamicField(settings, id, this)
+        : new StaticField(settings, this, id); 
+    }
 
     setupSubfields = (): Field[] => {
         return this.settings.subfields?.map((fieldSettings, index) => {
-            const id = Number(`${this.id}${index}`);
-            return fieldSettings.viewType === ViewType.FREEFORM || fieldSettings.viewType === ViewType.CAROUSEL3D
-                ? new DynamicField(fieldSettings, id, this)
-                : new StaticField(fieldSettings, this, id);
+            return this.setupField(fieldSettings, index);
         }) || [];
     }
 
@@ -67,6 +109,26 @@ export abstract class Field {
 
     abstract matches(cols: Col[]): Array<number>;
 
+    dispose = () => {
+        Object.values(this.disposers).forEach(disposer => disposer?.());
+    }
+
+    handleFieldUpdate = (newDocsList: Doc[]) => {
+        const currRenderedDocs: Set<Doc> = new Set();
+        this.subfields.forEach(field => currRenderedDocs.add(field.renderedDoc));
+        newDocsList.forEach(doc => {
+            if (!currRenderedDocs.has(doc)) {
+                this.addFieldFromDoc(doc);
+            }
+        });
+        currRenderedDocs.forEach(doc => {
+            if (!newDocsList.includes(doc)){
+                const fields = this.subfields.filter(field => field.renderedDoc === doc);
+                fields.forEach(field => this.removeField(field));
+            }
+        });
+    }
+
 }
 
 export type FieldSettings = {
@@ -99,7 +161,7 @@ export type FieldDimensions = {
     coord: {x: number, y: number};
 }
 
-export interface FieldOpts {
+export class FieldOpts {
     backgroundColor?: string;
     text_fontColor?: string;
     _layout_borderRounding?: number;
@@ -114,3 +176,7 @@ export interface FieldOpts {
     textTransform?: 'uppercase' | 'lowercase';
     fieldViewType?: 'freeform' | 'stacked';
 }
+function StringCast(arg0: unknown): undefined {
+    throw new Error("Function not implemented.");
+}
+
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
index 88115c529..94ff7b8e8 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
@@ -14,7 +14,6 @@ import { makeAutoObservable, reaction } from "mobx";
 import { IDisposer } from "mobx-utils";
 
 export class StaticField extends Field {
-    private disposers: { [name: string]: IDisposer } = {};
 
     private content: string;
     private contentType: FieldContentType | undefined;
@@ -31,33 +30,10 @@ export class StaticField extends Field {
         this.parent = parent;
         this.dimensions = FieldUtils.getLocalDimensions({tl: settings.tl, br: settings.br}, this.parent.getDimensions);
         this.content = '';
-        this.subfields = this.setupSubfields();
         this.renderedDocument = this.setupRenderedDoc();
         this.storedAttributes = new DocumentOptions();
-
-        this.disposers.fieldList = reaction(
-            () => DocListCast(this.renderedDocument[Doc.LayoutFieldKey(this.renderedDocument)]),
-            docs => {
-                this.handleFieldUpdate(docs);
-            }
-        );
-    };
-
-    get getSubfields(): Field[] { return this.subfields ?? []; };
-
-    get getAllSubfields(): Field[] {
-        let fields: Field[] = [];
-        this.subfields?.forEach(field => {
-            fields.push(field);
-            fields = fields.concat(field.getAllSubfields);
-        });
-        return fields;
     };
 
-    get getDescription(): string {
-        return this.settings.description ?? '';
-    }
-
     setContent = (newContent: string, type?: FieldContentType) => { 
         this.content = newContent;
         if (type) this.contentType = type;
@@ -70,35 +46,6 @@ export class StaticField extends Field {
         field.setContent('', this.contentType);
     }
 
-    setupSubfields = (): Field[] => {
-        return this.settings.subfields?.map((fieldSettings, index) => {
-            const id = Number(`${this.id}${index}`);
-            return fieldSettings.viewType === ViewType.FREEFORM || fieldSettings.viewType === ViewType.CAROUSEL3D
-                ? new DynamicField(fieldSettings, id, this)
-                : new StaticField(fieldSettings, this, id);
-        }) || [];
-    }
-
-    dispose = () => {
-        Object.values(this.disposers).forEach(disposer => disposer?.());
-    }
-
-    handleFieldUpdate = (newDocsList: Doc[]) => {
-        const currRenderedDocs: Set<Doc> = new Set();
-        this.subfields.forEach(field => currRenderedDocs.add(field.renderedDoc));
-        newDocsList.forEach(doc => {
-            if (!currRenderedDocs.has(doc)) {
-                this.addField(doc);
-            }
-        });
-        currRenderedDocs.forEach(doc => {
-            if (!newDocsList.includes(doc)){
-                const fields = this.subfields.filter(field => field.renderedDoc === doc);
-                fields.forEach(field => this.removeField(field));
-            }
-        });
-    }
-
     matches = (cols: Col[]): number[] => {
         const colMatchesField = (col: Col) => {
             const isMatch: boolean = (
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
index add588046..e079af4de 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
@@ -12,7 +12,7 @@ import { IDisposer } from "mobx-utils";
 
 export class Template {
 
-    private mainField: DynamicField;
+    mainField: DynamicField;
     private settings: FieldSettings;
 
     constructor(templateInfo: FieldSettings) {
@@ -24,7 +24,12 @@ export class Template {
     get childFields(): Field[] { return this.mainField.getSubfields };
     get allFields(): Field[] { return this.mainField.getAllSubfields };
     get contentFields(): Field[] { return this.allFields.filter(field => field.getViewType === ViewType.STATIC) };
-    get doc(){ return this.mainField.renderedDoc(); };
+    get doc(){ return this.mainField.renderedDoc; };
+    get title() { return this.mainField.getTitle() };
+
+    cleanup = () => {
+        //dispose each subfields disposers, etc.
+    }
 
     cloneBase = () => {
         const clone: Template = new Template(this.settings);
@@ -76,7 +81,7 @@ export class Template {
 
     renderUpdates = () => {
         this.allFields.forEach(field => {
-            field.updateRenderedDoc(field.renderedDoc());
+            field.updateRenderedDoc(field.renderedDoc);
         });
     };
 
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.tsx
index 310b19890..413c3082e 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.tsx
@@ -30,6 +30,6 @@ export class TemplateManager {
 
     removeTemplate = (template: Template) => {
         this.templates.splice(this.templates.indexOf(template), 1);
-        template.dispose();
+        template.cleanup();
     }
 }
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From a79431a47aa7fdff8e55ff653f28dd23c9af4650 Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Sun, 15 Dec 2024 05:13:35 -0500
Subject: Temprarily reverted static field rerendering changes; Persistent
 rendereddoc now working for dynamic field; work on making adding fields
 functional

---
 .../DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx   |  20 +--
 .../DocCreatorMenu/FieldTypes/DynamicField.tsx     |  33 +++--
 .../DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx |  79 +++++++----
 .../DocCreatorMenu/FieldTypes/FieldUtils.tsx       |  13 +-
 .../DocCreatorMenu/FieldTypes/StaticField.tsx      | 158 +++++++++++----------
 .../nodes/DataVizBox/DocCreatorMenu/Template.tsx   |   8 +-
 6 files changed, 178 insertions(+), 133 deletions(-)

(limited to 'src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx')

diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
index d8a71a610..69c896ccf 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
@@ -53,12 +53,11 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
     private templateManager: TemplateManager; 
 
-    @observable _fullyRenderedDocs: Doc[] = [];
-    @observable _renderedDocCollectionPreview: Doc | undefined = undefined;
-    @observable _renderedDocCollection: Doc | undefined = undefined;
-    @observable _docsRendering: boolean = false;
+    @observable _fullyRenderedDocs: Doc[] = []; // collection of templates filled in with content
+    @observable _renderedDocCollection: Doc | undefined = undefined; // fullyRenderedDocs in a parent collection
+    @observable _docsRendering: boolean = false; // dictates loading symbol
 
-    @observable _userTemplates: {template: Template, doc: Doc}[] = []; //!!! used to keep track of all templates, should be refactored to work with actual templates and not docs
+    @observable _userTemplates: {template: Template, doc: Doc}[] = []; 
     @observable _selectedTemplate: Template | undefined = undefined;
     @observable _currEditingTemplate: Template | undefined = undefined;
 
@@ -66,11 +65,9 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     @observable _selectedCols: { title: string; type: string; desc: string }[] | undefined = [];
 
     @observable _layout: { type: LayoutType; yMargin: number; xMargin: number; columns?: number; repeat: number } = { type: LayoutType.FREEFORM, yMargin: 10, xMargin: 10, columns: 3, repeat: 0 };
-    @observable _layoutPreviewScale: number = 1;
     @observable _savedLayouts: DataVizTemplateLayout[] = [];
     @observable _expandedPreview: Doc | undefined = undefined;
 
-    @observable _suggestedTemplates: Template[] = [];
     @observable _suggestedTemplatePreviews: {doc: Doc, template: Template}[] = [];
     @observable _GPTOpt: boolean = false;
     @observable _callCount: number = 0;
@@ -110,10 +107,8 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         this._dataViz = dataViz;
         this._selectedTemplate = undefined;
         this._renderedDocCollection = undefined;
-        this._renderedDocCollectionPreview = undefined;
         this._fullyRenderedDocs = [];
         this._suggestedTemplatePreviews = [];
-        this._suggestedTemplates = [];
         this._userCreatedFields = [];
     };
     @action addUserTemplate = (template: Template) => {
@@ -129,7 +124,6 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         this._userTemplates = this._userTemplates.map(t => { return t.template === preview.template ? preview : t }); //prettier-ignore
     };
     @action setSuggestedTemplates = (templates: Template[]) => {
-        this._suggestedTemplates = templates;
         this._suggestedTemplatePreviews = templates.map(template => {return {template: template, doc: template.getRenderedDoc()}}); //prettier-ignore
     };
 
@@ -399,7 +393,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
     testTemplate = async () => {
 
-        const obj = new DocumentOptions();
+        this._suggestedTemplatePreviews = this.templateManager.templates.map(template => {return {template: template, doc: template.getRenderedDoc()}}); //prettier-ignore
 
         //console.log(this.templateManager.templates)
 
@@ -761,7 +755,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     
         const renderedDocs = await Promise.all(promises);
 
-        this._docsRendering = false;
+        this._docsRendering = false; // removes loading indicator
 
         return renderedDocs;
     }
@@ -1110,7 +1104,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                     <ReactLoading type="spin" color={StrCast(Doc.UserDoc().userVariantColor)} height={30} width={30} />
                 </div> 
             </div>
-            ) : !this._renderedDocCollection? null : (
+            ) : !this._renderedDocCollection ? null : (
             <div className="docCreatorMenu-layout-preview-window-wrapper" id={String(id) ?? undefined}>
                 <DocumentView
                     Document={this._renderedDocCollection}
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
index 681e1d48c..c0bebccb5 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
@@ -1,4 +1,4 @@
-import { makeAutoObservable, reaction } from "mobx";
+import { makeAutoObservable, makeObservable, reaction } from "mobx";
 import { Doc, DocListCast } from "../../../../../../fields/Doc";
 import { Docs } from "../../../../../documents/Documents";
 import { Col } from "../DocCreatorMenu";
@@ -11,12 +11,12 @@ import { IDisposer } from "mobx-utils";
 export class DynamicField extends Field {
     private parent: Field;
     protected dimensions: FieldDimensions;
+    protected subfields: Field[];
 
     protected renderedDocument: Doc;
 
     constructor(settings: FieldSettings, id: number, parent?: Field) {
-        super(settings, id);
-        makeAutoObservable(this);
+        super(settings, id, FieldUtils.setupField);
         if (!parent) {
             this.parent = this;
             this.dimensions = {width: this.settings.br[0] - this.settings.tl[0], height: this.settings.br[1] - this.settings.tl[1], coord: {x: this.settings.tl[0], y: this.settings.tl[1]}};
@@ -24,7 +24,8 @@ export class DynamicField extends Field {
             this.parent = parent;
             this.dimensions = FieldUtils.getLocalDimensions({tl: settings.tl, br: settings.br}, this.parent.getDimensions);
         }
-        this.renderedDocument = new Doc(); //!!!
+        this.subfields = this.setupSubfields(this);
+        this.renderedDocument = this.updateRenderedDoc(); //!!!
 
         // this.disposers.fieldList = reaction(
         //     () => DocListCast(this.doc[Doc.LayoutFieldKey(this.doc)]),
@@ -53,22 +54,32 @@ export class DynamicField extends Field {
     };
 
     updateRenderedDoc = (): Doc => {
+        console.log('dynamic field updated');
+        let doc: Doc;
+        const renderedSubfields: Doc[] = this.subfields.map(field => field.renderedDoc);
         switch (this.settings.viewType) {
             case ViewType.CAROUSEL3D:
-                const carouselDoc = Docs.Create.Carousel3DDocument(this.subfields.map(field => field.renderedDoc), {
+                doc = Docs.Create.Carousel3DDocument(renderedSubfields, {
                     title: this.title,
                 });
-                FieldUtils.applyBasicOpts(carouselDoc, this.dimensions, this.settings);
-                return carouselDoc;
+                FieldUtils.applyBasicOpts(doc, this.dimensions, this.settings);
+                break;
             case ViewType.FREEFORM:
-                const freeformDoc = Docs.Create.FreeformDocument(this.subfields.map(field => field.renderedDoc), {
+                doc = Docs.Create.FreeformDocument(renderedSubfields, {
                     title: this.title,
                 });
-                FieldUtils.applyBasicOpts(freeformDoc, this.dimensions, this.settings);
-                return freeformDoc;
+                FieldUtils.applyBasicOpts(doc, this.dimensions, this.settings);
+                break;
             default:
-                return new Doc();
+                doc = Docs.Create.Carousel3DDocument(renderedSubfields, {
+                    title: this.title,
+                });
+                FieldUtils.applyBasicOpts(doc, this.dimensions, this.settings);
+            break;
         }
+
+        this.renderedDocument = doc;
+        return doc;
     }
 
 }
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
index 4d0aa10c8..23b36d680 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
@@ -1,17 +1,16 @@
-import { makeAutoObservable, reaction } from "mobx";
+import { makeAutoObservable, makeObservable, reaction } from "mobx";
 import { Doc, DocListCast } from "../../../../../../fields/Doc";
 import { Col } from "../DocCreatorMenu";
 import { TemplateFieldSize, TemplateFieldType } from "../TemplateBackend";
-import { DynamicField } from "./DynamicField";
-import { FieldUtils } from "./FieldUtils";
-import { StaticField } from "./StaticField";
 import { IDisposer } from "mobx-utils";
 import { DocumentType } from "../../../../../documents/DocumentTypes";
 
 export abstract class Field {
+
     protected disposers: { [name: string]: IDisposer } = {};
+    private setupField: (settings: FieldSettings, index: number, parent: Field) => Field;
 
-    protected subfields: Field[];
+    protected abstract subfields: Field[];
 
     protected abstract renderedDocument: Doc;
 
@@ -21,13 +20,11 @@ export abstract class Field {
 
     protected abstract dimensions: FieldDimensions;
 
-    constructor(settings: FieldSettings, id: number) {
-        makeAutoObservable(this);
-        
+    constructor(settings: FieldSettings, id: number, fieldFactory: (settings: FieldSettings, index: number, parent: Field) => Field) {
+        this.setupField = fieldFactory;
         this.id = id;
         this.settings = settings;
         this.title = settings.title ?? '';
-        this.subfields = this.setupSubfields();
 
         this.disposers.fieldList = reaction(
             () => DocListCast(this.renderedDocument[Doc.LayoutFieldKey(this.renderedDocument)]),
@@ -47,7 +44,7 @@ export abstract class Field {
         return fields;
     };
 
-    get renderedDoc() { return this.renderedDocument };
+    get renderedDoc(){ return this.renderedDocument };
     get getDimensions() { return this.dimensions };
     get getID() { return this.id };
     get getViewType() { return this.settings.viewType };
@@ -62,6 +59,10 @@ export abstract class Field {
     abstract setContent(content: string, type?: FieldContentType): void;
     abstract getContent(): string;
 
+    setupFieldChangeReaction = () => {
+
+    }
+
     addFieldFromDoc = (doc: Doc) => {
         const settings: FieldSettings = {
             tl: [Number(doc._x), Number(doc._y)],
@@ -71,15 +72,48 @@ export abstract class Field {
         };
 
         Object.getOwnPropertyNames(FieldOpts.prototype).forEach(([key, value]) => {
-            settings.opts[key as keyof FieldOpts] = StringCast(doc[key]);
+            switch (key) {
+                case 'text_fontColor':
+                case 'backgroundColor':
+                case 'borderWidth':
+                case 'borderColor':
+                    settings.opts[key] = String(doc[key]);
+                    break;
+            
+                case '_layout_borderRounding':
+                case 'opacity':
+                case '_rotation':
+                    settings.opts[key] = Number(doc[key]);
+                    break;
+            
+                case 'contentBold':
+                    settings.opts[key] = Boolean(doc[key]);
+                    break;
+            
+                case 'hCentering':
+                    settings.opts[key] = String(doc[key]) as 'h-left' | 'h-center' | 'h-right';
+                    break;
+                case 'contentYCentering':
+                    settings.opts[key] = String(doc[key]) as 'top' | 'center' | 'bottom';
+                    break;
+                case 'textTransform':
+                    settings.opts[key] = String(doc[key]) as 'uppercase' | 'lowercase';
+                    break;
+                case 'fieldViewType':
+                    settings.opts[key] = String(doc[key]) as 'freeform' | 'stacked';
+                    break;
+            
+                default:
+                    break;
+            }
         });
-
-        const newField = this.setupField(settings, this.subfields.length)
+        
+        const newField: Field = this.setupField(settings, this.subfields.length, this);
         this.subfields.push(newField);
     };
 
     addField = (type?: FieldContentType) => {
-
+        
     }
 
     removeField = (field: Field) => {
@@ -87,22 +121,16 @@ export abstract class Field {
         field.dispose();
     };
 
-    private setupField = (settings: FieldSettings, index: number): Field => { 
-        const id = Number(`${this.id}${index}`);
-        return settings.viewType === ViewType.FREEFORM || settings.viewType === ViewType.CAROUSEL3D
-        ? new DynamicField(settings, id, this)
-        : new StaticField(settings, this, id); 
-    }
-
-    setupSubfields = (): Field[] => {
+    setupSubfields = (parent: Field): Field[] => {
         return this.settings.subfields?.map((fieldSettings, index) => {
-            return this.setupField(fieldSettings, index);
+            return this.setupField(fieldSettings, index, parent);
         }) || [];
     }
 
     applyAttributes(field: Field) {
         field.setTitle(this.title);
         field.updateRenderedDoc(this.renderedDoc);
+        console.log('set width to:', String(this.renderedDoc._width));
     }
 
     abstract updateRenderedDoc(oldDoc?: Doc): void;
@@ -114,6 +142,7 @@ export abstract class Field {
     }
 
     handleFieldUpdate = (newDocsList: Doc[]) => {
+        console.log('handlefielduodate called');
         const currRenderedDocs: Set<Doc> = new Set();
         this.subfields.forEach(field => currRenderedDocs.add(field.renderedDoc));
         newDocsList.forEach(doc => {
@@ -176,7 +205,3 @@ export class FieldOpts {
     textTransform?: 'uppercase' | 'lowercase';
     fieldViewType?: 'freeform' | 'stacked';
 }
-function StringCast(arg0: unknown): undefined {
-    throw new Error("Function not implemented.");
-}
-
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
index 507790977..125624321 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
@@ -2,10 +2,13 @@ import { Doc } from "../../../../../../fields/Doc";
 import { ComputedField, ScriptField } from "../../../../../../fields/ScriptField";
 import { Col } from "../DocCreatorMenu";
 import { TemplateFieldSize, TemplateFieldType, TemplateLayouts } from "../TemplateBackend";
-import { FieldDimensions, FieldSettings } from "./Field";
+import { DynamicField } from "./DynamicField";
+import { Field, FieldDimensions, FieldSettings, ViewType } from "./Field";
+import { StaticField } from "./StaticField";
 
 export class FieldUtils {
     public static getLocalDimensions = (coords: { tl: [number, number]; br: [number, number] }, parentDimensions: FieldDimensions): FieldDimensions => {
+        console.log('parent dimensions', parentDimensions);
         const l = (coords.tl[0] * parentDimensions.width) / 2;
         const t = coords.tl[1] * parentDimensions.height / 2; //prettier-ignore
         const r = (coords.br[0] * parentDimensions.width) / 2;
@@ -16,7 +19,13 @@ export class FieldUtils {
         return { width, height, coord };
     };
 
-
+    public static setupField = (settings: FieldSettings, index: number, parent: Field): Field => { 
+        console.log('settings', settings);
+        const id = Number(`${parent.getID}${index}`);
+        return settings.viewType === ViewType.FREEFORM || settings.viewType === ViewType.CAROUSEL3D
+        ? new DynamicField(settings, id, parent)
+        : new StaticField(settings, parent, id); 
+    }
 
     public static textProperties: string[] = [
         "textTransform",
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
index 94ff7b8e8..b0ee537e7 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
@@ -10,7 +10,7 @@ import { Field, FieldContentType, FieldDimensions, FieldSettings, ViewType } fro
 import { indexOf } from "lodash";
 import { ScriptField } from "../../../../../../fields/ScriptField";
 import { StrCast } from "../../../../../../fields/Types";
-import { makeAutoObservable, reaction } from "mobx";
+import { makeAutoObservable, makeObservable, reaction } from "mobx";
 import { IDisposer } from "mobx-utils";
 
 export class StaticField extends Field {
@@ -18,6 +18,7 @@ export class StaticField extends Field {
     private content: string;
     private contentType: FieldContentType | undefined;
     protected renderedDocument: Doc;
+    protected subfields: Field[];
 
     private storedAttributes: Record<string, any>;
 
@@ -25,12 +26,12 @@ export class StaticField extends Field {
     protected dimensions: FieldDimensions;
 
     constructor(settings: FieldSettings, parent: Field, id: number) {
-        super(settings, id);
-        makeAutoObservable(this);
+        super(settings, id, FieldUtils.setupField);
         this.parent = parent;
         this.dimensions = FieldUtils.getLocalDimensions({tl: settings.tl, br: settings.br}, this.parent.getDimensions);
         this.content = '';
-        this.renderedDocument = this.setupRenderedDoc();
+        this.subfields = this.setupSubfields(this);
+        this.renderedDocument = this.updateRenderedDoc();
         this.storedAttributes = new DocumentOptions();
     };
 
@@ -66,96 +67,97 @@ export class StaticField extends Field {
         return matches;
     };
 
-    // updateRenderedDoc = (oldDoc?: Doc): Doc => {
-    //     const opts = this.settings.opts;
+    updateRenderedDoc = (oldDoc?: Doc): Doc => {
+        console.log(' static field updated');
+        const opts = this.settings.opts;
 
-    //     if (!this.contentType) { this.contentType = FieldContentType.STRING };
+        if (!this.contentType) { this.contentType = FieldContentType.STRING };
 
-    //     let doc: Doc;
+        let doc: Doc;
 
-    //     switch (this.contentType) {
-    //         case FieldContentType.STRING:
-    //             const text = String(this.content);
-    //             doc = Docs.Create.TextDocument(text, {
-    //                 title: this.title,
-    //                 text_fontColor: oldDoc ? String(oldDoc.color) : opts.text_fontColor,
-    //                 contentBold: oldDoc ? Boolean(oldDoc.fontBold) : opts.contentBold,
-    //                 textTransform: oldDoc ? String(oldDoc.fontTransform) : opts.textTransform,
-    //                 color: oldDoc ? String(oldDoc.color) : opts.text_fontColor,
-    //                 _text_fontSize: `${FieldUtils.calculateFontSize(this.dimensions.width, this.dimensions.height, text, true)}`
-    //             });
-    //             FieldUtils.applyBasicOpts(doc, this.dimensions, this.settings, oldDoc);
-    //             break;
-    //         case FieldContentType.IMAGE:
-    //             const url = String(this.content);
-    //             doc = Docs.Create.ImageDocument(url, {
-    //                 title: this.title,
-    //                 _layout_fitWidth: false,
-    //             });
-    //             FieldUtils.applyBasicOpts(doc, this.dimensions, this.settings, oldDoc);
-    //             break;
-    //     }   
-
-    //     this.renderedDocument = doc;
-
-    //     return doc;
-    // };
+        switch (this.contentType) {
+            case FieldContentType.STRING:
+                const text = String(this.content);
+                doc = Docs.Create.TextDocument(text, {
+                    title: this.title,
+                    text_fontColor: oldDoc ? String(oldDoc.color) : opts.text_fontColor,
+                    contentBold: oldDoc ? Boolean(oldDoc.fontBold) : opts.contentBold,
+                    textTransform: oldDoc ? String(oldDoc.fontTransform) : opts.textTransform,
+                    color: oldDoc ? String(oldDoc.color) : opts.text_fontColor,
+                    _text_fontSize: `${FieldUtils.calculateFontSize(this.dimensions.width, this.dimensions.height, text, true)}`
+                });
+                FieldUtils.applyBasicOpts(doc, this.dimensions, this.settings, oldDoc);
+                break;
+            case FieldContentType.IMAGE:
+                const url = String(this.content);
+                doc = Docs.Create.ImageDocument(url, {
+                    title: this.title,
+                    _layout_fitWidth: false,
+                });
+                FieldUtils.applyBasicOpts(doc, this.dimensions, this.settings, oldDoc);
+                break;
+        }   
 
-    updateRenderedDoc = (currDoc?: Doc, forceRerender?: boolean) => {
+        this.renderedDocument = doc;
 
-        if (!this.contentType) { this.contentType = FieldContentType.STRING };
+        return doc;
+    };
 
-        let doc: Doc;
+    // updateRenderedDoc = (currDoc?: Doc, forceRerender?: boolean) => {
 
-        // if (this.shouldRerender() || forceRerender) {
-        // } else {
-        //     this.updateStoredAttributes(this.renderedDocument);
-        // }
+    //     if (!this.contentType) { this.contentType = FieldContentType.STRING };
 
-        this.updateStoredAttributes(this.renderedDocument);
+    //     let doc: Doc;
 
-        let list: string[] = Object.entries(this.storedAttributes).map(([key, value]) => `${key}: ${value}`);
-        console.log(list);
+    //     // if (this.shouldRerender() || forceRerender) {
+    //     // } else {
+    //     //     this.updateStoredAttributes(this.renderedDocument);
+    //     // }
 
-            switch (this.contentType) {
-                case FieldContentType.STRING:
-                    const text = String(this.content);
-                    this.storedAttributes._text_fontSize = `${FieldUtils.calculateFontSize(this.dimensions.width, this.dimensions.height, this.content, true)}`
-                    doc = Docs.Create.TextDocument(text, this.storedAttributes);
-                    break;
-                case FieldContentType.IMAGE:
-                    const url = String(this.content);
-                    doc = Docs.Create.ImageDocument(url, this.storedAttributes);
-                    break;
-            } 
-            doc._layout_hideScroll = true;  
+    //     this.updateStoredAttributes(this.renderedDocument);
 
+    //     let list: string[] = Object.entries(this.storedAttributes).map(([key, value]) => `${key}: ${value}`);
+    //     console.log(list);
 
-            console.log(StrCast(doc.backgroundColor), StrCast(doc._rotation));
+    //         switch (this.contentType) {
+    //             case FieldContentType.STRING:
+    //                 const text = String(this.content);
+    //                 this.storedAttributes._text_fontSize = `${FieldUtils.calculateFontSize(this.dimensions.width, this.dimensions.height, this.content, true)}`
+    //                 doc = Docs.Create.TextDocument(text, this.storedAttributes);
+    //                 break;
+    //             case FieldContentType.IMAGE:
+    //                 const url = String(this.content);
+    //                 doc = Docs.Create.ImageDocument(url, this.storedAttributes);
+    //                 break;
+    //         } 
+    //         doc._layout_hideScroll = true;  
 
-            this.renderedDocument = doc;
 
-        //this.renderedDocument = doc;
-    };
+    //         console.log(StrCast(doc.backgroundColor), StrCast(doc._rotation));
 
-    private updateStoredAttributes = (currDoc?: Doc) => {
-        const opts = this.settings.opts;
-        console.log("num atts", Object.entries(this.storedAttributes).length);
-        Object.entries(this.storedAttributes).forEach(([key, value]) => {
-            key = String(key); 
-            if (currDoc && currDoc[key] !== undefined) {
-                this.storedAttributes[key] = currDoc[key];
-            } else if (opts[key as keyof typeof opts] !== undefined) {
-                this.storedAttributes[key] = opts[key as keyof typeof opts];
-            }
-        });
-    }
+    //         this.renderedDocument = doc;
 
-    private shouldRerender = (): boolean => {
-        return FieldUtils.textProperties.some(property => 
-            this.renderedDocument[property] !== this.storedAttributes[property]
-        );
-    };
+    //     //this.renderedDocument = doc;
+    // };
+
+    // private updateStoredAttributes = (currDoc?: Doc) => {
+    //     const opts = this.settings.opts;
+    //     console.log("num atts", Object.entries(this.storedAttributes).length);
+    //     Object.entries(this.storedAttributes).forEach(([key, value]) => {
+    //         key = String(key); 
+    //         if (currDoc && currDoc[key] !== undefined) {
+    //             this.storedAttributes[key] = currDoc[key];
+    //         } else if (opts[key as keyof typeof opts] !== undefined) {
+    //             this.storedAttributes[key] = opts[key as keyof typeof opts];
+    //         }
+    //     });
+    // }
+
+    // private shouldRerender = (): boolean => {
+    //     return FieldUtils.textProperties.some(property => 
+    //         this.renderedDocument[property] !== this.storedAttributes[property]
+    //     );
+    // };
 
     private setupRenderedDoc = (): Doc => {
         const docOptions: Record<string, any> = new DocumentOptions();
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
index e079af4de..0e1ddc28f 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
@@ -17,8 +17,9 @@ export class Template {
 
     constructor(templateInfo: FieldSettings) {
         makeAutoObservable(this);
-        this.mainField = this.setupMainField(templateInfo);
         this.settings = templateInfo;
+        this.mainField = this.setupMainField(templateInfo);
+        console.log(templateInfo);
     }
 
     get childFields(): Field[] { return this.mainField.getSubfields };
@@ -33,10 +34,13 @@ export class Template {
 
     cloneBase = () => {
         const clone: Template = new Template(this.settings);
-        clone.allFields.forEach(field => {
+        
+        clone.allFields.filter(field => field !== clone.mainField).forEach(field => {
+            console.log('id:', field.getID);
             const matchingField: Field = this.allFields.filter(f => f.getID === field.getID)[0];
             matchingField.applyAttributes(field);
         })
+        clone.mainField.updateRenderedDoc();
         return clone;
     }
 
-- 
cgit v1.2.3-70-g09d2


From f02559f86c339d069743590bcac0c6d5407ecba8 Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Thu, 19 Dec 2024 04:19:29 -0500
Subject: previewcollection updates automatically on closing editing window of
 selected template; removed redundant field updating now that everything is
 static; lots of comments to remove

---
 .../DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx   | 28 ++++++++++++++++------
 .../DocCreatorMenu/FieldTypes/DynamicField.tsx     |  5 ++--
 .../DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx | 14 +++++++----
 .../DocCreatorMenu/FieldTypes/FieldUtils.tsx       |  3 ++-
 .../DocCreatorMenu/FieldTypes/StaticField.tsx      |  4 ++--
 .../nodes/DataVizBox/DocCreatorMenu/Template.tsx   |  8 +------
 6 files changed, 39 insertions(+), 23 deletions(-)

(limited to 'src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx')

diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
index 69c896ccf..08583f594 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
@@ -118,7 +118,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         this._userTemplates = this._userTemplates.filter(info => info.template !== template);
     }
     @action updateTemplatePreview = (template: Template) => {
-        template.renderUpdates();
+        //template.renderUpdates();
         const preview = {template: template, doc: template.getRenderedDoc()};
         this._suggestedTemplatePreviews = this._suggestedTemplatePreviews.map(t => { return t.template === preview.template ? preview : t }); //prettier-ignore
         this._userTemplates = this._userTemplates.map(t => { return t.template === preview.template ? preview : t }); //prettier-ignore
@@ -361,15 +361,19 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         return undefined;
     }
 
+    @action updateRenderedPreviewCollection = async (template: Template) => {
+        this._fullyRenderedDocs = await this.createDocsFromTemplate(template) ?? [];
+        this.updateRenderedDocCollection();
+    }
+
     @action updateSelectedTemplate = async (template: Template) => {
         if (this._selectedTemplate === template) {
             this._selectedTemplate = undefined;
             return;
         } else {
             this._selectedTemplate = template;
-            template.renderUpdates();
-            this._fullyRenderedDocs = await this.createDocsFromTemplate(template) ?? [];
-            this.updateRenderedDocCollection();
+            //template.renderUpdates();
+            this.updateRenderedPreviewCollection(template);
         }
     };
 
@@ -759,6 +763,8 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
         return renderedDocs;
     }
+
+    
     
 
     addRenderedCollectionToMainview = () => {
@@ -814,9 +820,14 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                 {rendered}
                 <div className="right-buttons-panel">
                     <button className="docCreatorMenu-menu-button section-reveal-options top-right" onPointerDown={e => this.setUpButtonClick(e, () => {
-                        this._currEditingTemplate && this.updateTemplatePreview(this._currEditingTemplate); 
-                        this.setExpandedView(undefined)}
-                        )}>
+                        if (!this._currEditingTemplate) return; 
+                        if (this._currEditingTemplate === this._selectedTemplate) {
+                            this.updateTemplatePreview(this._currEditingTemplate);
+                            this.updateRenderedPreviewCollection(this._currEditingTemplate);
+                        }
+                        this.updateRenderedPreviewCollection(this._currEditingTemplate);
+                        this.setExpandedView(undefined);
+                        })}>
                         <FontAwesomeIcon icon="minimize" />
                     </button>
                     <button className="docCreatorMenu-menu-button section-reveal-options top-right-lower" onPointerDown={e => this.setUpButtonClick(e, () => {this._currEditingTemplate?.resetToBase(); this.setExpandedView(this._currEditingTemplate);})}>
@@ -1061,6 +1072,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     @type the type of collection the docs should render to (ie. freeform, carousel, card)
      */
     updateRenderedDocCollection = () => {
+        console.log('called');
         if (!this._fullyRenderedDocs) return;
 
         const { horizontalSpan, verticalSpan } = this.previewInfo;
@@ -1094,6 +1106,8 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         this.applyLayout(collection, this._fullyRenderedDocs);
 
         this._renderedDocCollection = collection;
+
+        console.log('changed');
     }
 
     layoutPreviewContents = (id?: number) => {
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
index c0bebccb5..0596e6d44 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
@@ -9,14 +9,14 @@ import { StaticField } from "./StaticField";
 import { IDisposer } from "mobx-utils";
 
 export class DynamicField extends Field {
-    private parent: Field;
+    protected parent: Field;
     protected dimensions: FieldDimensions;
     protected subfields: Field[];
 
     protected renderedDocument: Doc;
 
     constructor(settings: FieldSettings, id: number, parent?: Field) {
-        super(settings, id, FieldUtils.setupField);
+        super(settings, id, FieldUtils.setupField, parent);
         if (!parent) {
             this.parent = this;
             this.dimensions = {width: this.settings.br[0] - this.settings.tl[0], height: this.settings.br[1] - this.settings.tl[1], coord: {x: this.settings.tl[0], y: this.settings.tl[1]}};
@@ -24,6 +24,7 @@ export class DynamicField extends Field {
             this.parent = parent;
             this.dimensions = FieldUtils.getLocalDimensions({tl: settings.tl, br: settings.br}, this.parent.getDimensions);
         }
+        console.log('new field dimensions: ', this.dimensions);
         this.subfields = this.setupSubfields(this);
         this.renderedDocument = this.updateRenderedDoc(); //!!!
 
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
index 23b36d680..9fd0fae19 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
@@ -14,14 +14,16 @@ export abstract class Field {
 
     protected abstract renderedDocument: Doc;
 
+    protected parent?: Field;
     protected id: number;
     protected settings: FieldSettings;
     protected title: string = '';
 
     protected abstract dimensions: FieldDimensions;
 
-    constructor(settings: FieldSettings, id: number, fieldFactory: (settings: FieldSettings, index: number, parent: Field) => Field) {
+    constructor(settings: FieldSettings, id: number, fieldFactory: (settings: FieldSettings, index: number, parent: Field) => Field, parent?: Field) {
         this.setupField = fieldFactory;
+        this.parent = parent ? parent : this;
         this.id = id;
         this.settings = settings;
         this.title = settings.title ?? '';
@@ -64,9 +66,10 @@ export abstract class Field {
     }
 
     addFieldFromDoc = (doc: Doc) => {
+        const par = this.renderedDocument;
         const settings: FieldSettings = {
-            tl: [Number(doc._x), Number(doc._y)],
-            br: [Number(doc._x) + Number(doc._width), Number(doc._y) + Number(doc._height)],
+            tl: [Number(doc._x) / Number(par._width), Number(doc._y) / Number(par._height)],
+            br: [(Number(doc._x) + Number(doc._width)) / Number(par._width), (Number(doc._y) + Number(doc._height)) / Number(par._height)],
             viewType: doc.type === DocumentType.COL ? ViewType.FREEFORM : ViewType.STATIC,
             opts: {},
         };
@@ -129,8 +132,11 @@ export abstract class Field {
 
     applyAttributes(field: Field) {
         field.setTitle(this.title);
+        //this.updateRenderedDoc(this.renderedDoc);
         field.updateRenderedDoc(this.renderedDoc);
-        console.log('set width to:', String(this.renderedDoc._width));
+        field.subfields = this.subfields;
+        console.log('id:', this.id, 'set width to:', Number(this.renderedDoc._width));
+        console.log('set height to:', Number(this.renderedDoc._height));
     }
 
     abstract updateRenderedDoc(oldDoc?: Doc): void;
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
index 125624321..11e35746f 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
@@ -8,7 +8,7 @@ import { StaticField } from "./StaticField";
 
 export class FieldUtils {
     public static getLocalDimensions = (coords: { tl: [number, number]; br: [number, number] }, parentDimensions: FieldDimensions): FieldDimensions => {
-        console.log('parent dimensions', parentDimensions);
+        console.log('parent dimensions', parentDimensions, 'coords: ', coords);
         const l = (coords.tl[0] * parentDimensions.width) / 2;
         const t = coords.tl[1] * parentDimensions.height / 2; //prettier-ignore
         const r = (coords.br[0] * parentDimensions.width) / 2;
@@ -16,6 +16,7 @@ export class FieldUtils {
         const width = r - l;
         const height = b - t;
         const coord = { x: l, y: t };
+        console.log('width: ', width, 'height: ', height);
         return { width, height, coord };
     };
 
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
index b0ee537e7..0b2f437e8 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
@@ -22,11 +22,11 @@ export class StaticField extends Field {
 
     private storedAttributes: Record<string, any>;
 
-    private parent: Field;
+    protected parent: Field;
     protected dimensions: FieldDimensions;
 
     constructor(settings: FieldSettings, parent: Field, id: number) {
-        super(settings, id, FieldUtils.setupField);
+        super(settings, id, FieldUtils.setupField, parent);
         this.parent = parent;
         this.dimensions = FieldUtils.getLocalDimensions({tl: settings.tl, br: settings.br}, this.parent.getDimensions);
         this.content = '';
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
index 0e1ddc28f..9ebec9144 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
@@ -34,7 +34,7 @@ export class Template {
 
     cloneBase = () => {
         const clone: Template = new Template(this.settings);
-        
+        this.mainField.applyAttributes(clone.mainField);
         clone.allFields.filter(field => field !== clone.mainField).forEach(field => {
             console.log('id:', field.getID);
             const matchingField: Field = this.allFields.filter(f => f.getID === field.getID)[0];
@@ -83,12 +83,6 @@ export class Template {
         return summary;
     }
 
-    renderUpdates = () => {
-        this.allFields.forEach(field => {
-            field.updateRenderedDoc(field.renderedDoc);
-        });
-    };
-
     resetToBase = () => {
         this.allFields.forEach(field => {
             field.updateRenderedDoc();
-- 
cgit v1.2.3-70-g09d2


From 12bd4313d188c5da1a68c1c7dbc3f7a3d01ff0d0 Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Thu, 19 Dec 2024 05:40:21 -0500
Subject: simplified suggestedTemplates field by removing unecessary caching of
 rendered doc

---
 .../DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx   | 23 +++++++---------------
 .../DocCreatorMenu/FieldTypes/DynamicField.tsx     |  5 +++--
 .../DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx |  5 +++--
 .../DocCreatorMenu/FieldTypes/FieldUtils.tsx       |  6 +++---
 .../nodes/DataVizBox/DocCreatorMenu/Template.tsx   |  1 +
 5 files changed, 17 insertions(+), 23 deletions(-)

(limited to 'src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx')

diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
index 08583f594..505b7bd46 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
@@ -68,7 +68,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     @observable _savedLayouts: DataVizTemplateLayout[] = [];
     @observable _expandedPreview: Doc | undefined = undefined;
 
-    @observable _suggestedTemplatePreviews: {doc: Doc, template: Template}[] = [];
+    @observable _suggestedTemplates: Template[] = [];
     @observable _GPTOpt: boolean = false;
     @observable _callCount: number = 0;
     @observable _GPTLoading: boolean = false;
@@ -108,7 +108,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         this._selectedTemplate = undefined;
         this._renderedDocCollection = undefined;
         this._fullyRenderedDocs = [];
-        this._suggestedTemplatePreviews = [];
+        this._suggestedTemplates = [];
         this._userCreatedFields = [];
     };
     @action addUserTemplate = (template: Template) => {
@@ -117,14 +117,8 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     @action removeUserTemplate = (template: Template) => {
         this._userTemplates = this._userTemplates.filter(info => info.template !== template);
     }
-    @action updateTemplatePreview = (template: Template) => {
-        //template.renderUpdates();
-        const preview = {template: template, doc: template.getRenderedDoc()};
-        this._suggestedTemplatePreviews = this._suggestedTemplatePreviews.map(t => { return t.template === preview.template ? preview : t }); //prettier-ignore
-        this._userTemplates = this._userTemplates.map(t => { return t.template === preview.template ? preview : t }); //prettier-ignore
-    };
     @action setSuggestedTemplates = (templates: Template[]) => {
-        this._suggestedTemplatePreviews = templates.map(template => {return {template: template, doc: template.getRenderedDoc()}}); //prettier-ignore
+        this._suggestedTemplates = templates; //prettier-ignore
     };
 
     @computed get docsToRender() {
@@ -397,7 +391,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
     testTemplate = async () => {
 
-        this._suggestedTemplatePreviews = this.templateManager.templates.map(template => {return {template: template, doc: template.getRenderedDoc()}}); //prettier-ignore
+        this._suggestedTemplates = this.templateManager.templates; //prettier-ignore
 
         //console.log(this.templateManager.templates)
 
@@ -822,10 +816,8 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                     <button className="docCreatorMenu-menu-button section-reveal-options top-right" onPointerDown={e => this.setUpButtonClick(e, () => {
                         if (!this._currEditingTemplate) return; 
                         if (this._currEditingTemplate === this._selectedTemplate) {
-                            this.updateTemplatePreview(this._currEditingTemplate);
                             this.updateRenderedPreviewCollection(this._currEditingTemplate);
                         }
-                        this.updateRenderedPreviewCollection(this._currEditingTemplate);
                         this.setExpandedView(undefined);
                         })}>
                         <FontAwesomeIcon icon="minimize" />
@@ -839,7 +831,6 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     }
 
     get templatesPreviewContents() {
-        const renderedTemplates: Doc[] = [];
 
         const GPTOptions = <div></div>;
 
@@ -889,8 +880,8 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                                         <ReactLoading type="spin" color={StrCast(Doc.UserDoc().userVariantColor)} height={30} width={30} />
                                     </div>
                                 ) : (
-                                    this._suggestedTemplatePreviews
-                                        .map(({doc, template}) => (
+                                    this._suggestedTemplates
+                                        .map(template => (
                                             <div
                                                 className="docCreatorMenu-preview-window"
                                                 style={{
@@ -910,7 +901,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                                                 <button className="option-button right" onPointerDown={e => this.setUpButtonClick(e, () => this.addUserTemplate(template))}>
                                                     <FontAwesomeIcon icon="plus" color="white" />
                                                 </button>
-                                                {previewDoc(doc, template)}
+                                                {previewDoc(template.getRenderedDoc(), template)}
                                             </div>
                                         ))
                                 )}
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
index 0596e6d44..c751c91bd 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
@@ -24,7 +24,7 @@ export class DynamicField extends Field {
             this.parent = parent;
             this.dimensions = FieldUtils.getLocalDimensions({tl: settings.tl, br: settings.br}, this.parent.getDimensions);
         }
-        console.log('new field dimensions: ', this.dimensions);
+        //console.log('new field dimensions: ', this.dimensions);
         this.subfields = this.setupSubfields(this);
         this.renderedDocument = this.updateRenderedDoc(); //!!!
 
@@ -55,7 +55,8 @@ export class DynamicField extends Field {
     };
 
     updateRenderedDoc = (): Doc => {
-        console.log('dynamic field updated');
+        
+        //console.log('dynamic field updated');
         let doc: Doc;
         const renderedSubfields: Doc[] = this.subfields.map(field => field.renderedDoc);
         switch (this.settings.viewType) {
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
index 9fd0fae19..1dd442c97 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
@@ -66,6 +66,7 @@ export abstract class Field {
     }
 
     addFieldFromDoc = (doc: Doc) => {
+        console.log('add field called');
         const par = this.renderedDocument;
         const settings: FieldSettings = {
             tl: [Number(doc._x) / Number(par._width), Number(doc._y) / Number(par._height)],
@@ -135,8 +136,8 @@ export abstract class Field {
         //this.updateRenderedDoc(this.renderedDoc);
         field.updateRenderedDoc(this.renderedDoc);
         field.subfields = this.subfields;
-        console.log('id:', this.id, 'set width to:', Number(this.renderedDoc._width));
-        console.log('set height to:', Number(this.renderedDoc._height));
+        console.log('id:', this.id, 'set width to:', Number(this.renderedDoc.width));
+        console.log('set height to:', Number(this.renderedDoc.height));
     }
 
     abstract updateRenderedDoc(oldDoc?: Doc): void;
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
index 11e35746f..27ea8e1f5 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
@@ -8,7 +8,7 @@ import { StaticField } from "./StaticField";
 
 export class FieldUtils {
     public static getLocalDimensions = (coords: { tl: [number, number]; br: [number, number] }, parentDimensions: FieldDimensions): FieldDimensions => {
-        console.log('parent dimensions', parentDimensions, 'coords: ', coords);
+        //console.log('parent dimensions', parentDimensions, 'coords: ', coords);
         const l = (coords.tl[0] * parentDimensions.width) / 2;
         const t = coords.tl[1] * parentDimensions.height / 2; //prettier-ignore
         const r = (coords.br[0] * parentDimensions.width) / 2;
@@ -16,12 +16,12 @@ export class FieldUtils {
         const width = r - l;
         const height = b - t;
         const coord = { x: l, y: t };
-        console.log('width: ', width, 'height: ', height);
+        //console.log('width: ', width, 'height: ', height);
         return { width, height, coord };
     };
 
     public static setupField = (settings: FieldSettings, index: number, parent: Field): Field => { 
-        console.log('settings', settings);
+        //console.log('settings', settings);
         const id = Number(`${parent.getID}${index}`);
         return settings.viewType === ViewType.FREEFORM || settings.viewType === ViewType.CAROUSEL3D
         ? new DynamicField(settings, id, parent)
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
index 9ebec9144..7515a39be 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
@@ -45,6 +45,7 @@ export class Template {
     }
 
     getRenderedDoc = () => {
+        console.log('called');
         const doc: Doc = this.doc;
         this.contentFields.forEach(field => {
             const title: string = field.getTitle();
-- 
cgit v1.2.3-70-g09d2


From 6c5d7c2a4584e73e17593cb54071c91bcf153cca Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Sun, 22 Dec 2024 04:37:25 -0500
Subject: changes for testing without using GPT

---
 src/client/views/nodes/DataVizBox/DataVizBox.tsx   |  8 ++--
 .../DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx   | 41 ++++++++++--------
 .../DocCreatorMenu/FieldTypes/DynamicField.tsx     |  4 --
 .../DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx |  4 +-
 .../DocCreatorMenu/FieldTypes/StaticField.tsx      | 14 ++----
 .../nodes/DataVizBox/DocCreatorMenu/Template.tsx   | 18 ++++----
 .../DataVizBox/DocCreatorMenu/TemplateBackend.tsx  | 50 ++++++++++++++--------
 .../DataVizBox/DocCreatorMenu/TemplateManager.tsx  |  1 -
 8 files changed, 74 insertions(+), 66 deletions(-)

(limited to 'src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx')

diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
index dececd1dc..117311b8c 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
@@ -411,10 +411,10 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
             },
             { fireImmediately: true }
         );
-        this._disposers.contentSummary = reaction(
-            () => this.records,
-            () => this.updateGPTSummary()
-        );
+        // this._disposers.contentSummary = reaction(
+        //     () => this.records,
+        //     () => this.updateGPTSummary()
+        // );
     }
 
     fetchData = () => {
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
index e1f53ec47..e8b80b7b5 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
@@ -115,14 +115,15 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         this._userTemplates.push(template);
     };
     @action removeUserTemplate = (template: Template) => {
-        this._userTemplates.splice(this._userTemplates.indexOf(t), 1);
+        this._userTemplates.splice(this._userTemplates.indexOf(template), 1);
     }
     @action setSuggestedTemplates = (templates: Template[]) => {
         this._suggestedTemplates = templates; //prettier-ignore
     };
 
     @computed get docsToRender() {
-        return this._selectedTemplate ? NumListCast(this._dataViz?.layoutDoc.dataViz_selectedRows) : [];
+        return [1, 2, 3, 4];
+        //this._selectedTemplate ? NumListCast(this._dataViz?.layoutDoc.dataViz_selectedRows) : []; !!! put this back for GPT rendering
     }
 
     @computed get rowsCount() {
@@ -357,6 +358,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
     @action updateRenderedPreviewCollection = async (template: Template) => {
         this._fullyRenderedDocs = await this.createDocsFromTemplate(template) ?? [];
+        console.log(this._fullyRenderedDocs);
         this.updateRenderedDocCollection();
     }
 
@@ -716,6 +718,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         });
     
         const processContent = async (content: {[title: string]: string}) => {
+
             const templateCopy = template.cloneBase(); 
 
             fields.filter(title => title).forEach(title => {
@@ -748,19 +751,23 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     
             return templateCopy.getRenderedDoc();
         };
+
+        const rows = [1, 2, 3, 4];
     
-        const promises = rowContents.map(content => processContent(content));
+        //const promises = rowContents.map(content => processContent(content));
     
+        const promises = rows.map(row => processContent({}));
+
         const renderedDocs = await Promise.all(promises);
 
         this._docsRendering = false; // removes loading indicator
 
+        console.log('docs: ', renderedDocs);
+        console.log('first doc height: ', renderedDocs[0]._height);
+
         return renderedDocs;
     }
 
-    
-    
-
     addRenderedCollectionToMainview = () => {
         const collection = this._renderedDocCollection;
         if (!collection) return;
@@ -822,7 +829,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                         })}>
                         <FontAwesomeIcon icon="minimize" />
                     </button>
-                    <button className="docCreatorMenu-menu-button section-reveal-options top-right-lower" onPointerDown={e => this.setUpButtonClick(e, () => {this._currEditingTemplate?.resetToBase(); this.setExpandedView(this._currEditingTemplate);})}>
+                    <button className="docCreatorMenu-menu-button section-reveal-options top-right-lower" onPointerDown={e => this.setUpButtonClick(e, () => {this._currEditingTemplate?.printFieldInfo();/*this._currEditingTemplate?.resetToBase();*/ this.setExpandedView(this._currEditingTemplate);})}>
                         <FontAwesomeIcon icon="arrows-rotate" color="white" />
                     </button>
                 </div>
@@ -1012,11 +1019,9 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         collection._height = verticalSpan;
         collection._width = horizontalSpan;
 
-        const layout = this._layout;
-        const columns: number = layout.columns ?? this.columnsCount;
-        const xGap: number = layout.xMargin;
-        const yGap: number = layout.yMargin;
-        // const repeat: number = templateInfo.layout.repeat;
+        const columns: number = this._layout.columns ?? this.columnsCount;
+        const xGap: number = this._layout.xMargin;
+        const yGap: number = this._layout.yMargin;
         const startX: number = -Number(collection._width)/2;
         const startY: number = -Number(collection._height)/2;
         const docHeight: number = Number(docs[0]._height);
@@ -1066,7 +1071,6 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         console.log('called');
         if (!this._fullyRenderedDocs) return;
 
-        const { horizontalSpan, verticalSpan } = this.previewInfo;
         //const largerSpan: number = horizontalSpan > verticalSpan ? horizontalSpan : verticalSpan;
 
         const collectionFactory = (): (docs: Doc[], options: DocumentOptions) => Doc => {
@@ -1086,19 +1090,22 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
             }
         }
 
-        const collection: Doc = collectionFactory()(this._fullyRenderedDocs, {
+        const collection = collectionFactory()(this._fullyRenderedDocs, {
             isDefaultTemplateDoc: true,
-            _height: verticalSpan,
-            _width: horizontalSpan,
             title: 'title',
             backgroundColor: 'gray',
+            x: 200,
+            y: 200
         });
 
         this.applyLayout(collection, this._fullyRenderedDocs);
 
         this._renderedDocCollection = collection;
 
-        console.log('changed');
+        const mainCollection = this._dataViz?.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionFreeFormView;
+        mainCollection.addDocument(collection);
+
+        console.log('changed to: ', collection);
     }
 
     layoutPreviewContents = (id?: number) => {
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
index c751c91bd..c244dd57c 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
@@ -1,12 +1,8 @@
-import { makeAutoObservable, makeObservable, reaction } from "mobx";
 import { Doc, DocListCast } from "../../../../../../fields/Doc";
 import { Docs } from "../../../../../documents/Documents";
 import { Col } from "../DocCreatorMenu";
-import { TemplateLayouts } from "../TemplateBackend";
 import { Field, FieldContentType, FieldDimensions, FieldSettings, ViewType } from "./Field";
 import { FieldUtils } from "./FieldUtils";
-import { StaticField } from "./StaticField";
-import { IDisposer } from "mobx-utils";
 
 export class DynamicField extends Field {
     protected parent: Field;
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
index 1dd442c97..2aa9f9032 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
@@ -136,8 +136,8 @@ export abstract class Field {
         //this.updateRenderedDoc(this.renderedDoc);
         field.updateRenderedDoc(this.renderedDoc);
         field.subfields = this.subfields;
-        console.log('id:', this.id, 'set width to:', Number(this.renderedDoc.width));
-        console.log('set height to:', Number(this.renderedDoc.height));
+        //console.log('id:', this.id, 'set width to:', Number(this.renderedDoc.width));
+        //console.log('set height to:', Number(this.renderedDoc.height));
     }
 
     abstract updateRenderedDoc(oldDoc?: Doc): void;
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
index 0b2f437e8..df997c8c5 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
@@ -1,17 +1,8 @@
-import { TbHospital } from "react-icons/tb";
 import { Doc, DocListCast } from "../../../../../../fields/Doc";
-import { FieldType } from "../../../../../../fields/ObjectField";
 import { Docs, DocumentOptions } from "../../../../../documents/Documents";
 import { Col } from "../DocCreatorMenu";
-import { Template } from "../Template";
-import { DynamicField } from "./DynamicField";
 import { FieldUtils } from "./FieldUtils";
 import { Field, FieldContentType, FieldDimensions, FieldSettings, ViewType } from "./Field";
-import { indexOf } from "lodash";
-import { ScriptField } from "../../../../../../fields/ScriptField";
-import { StrCast } from "../../../../../../fields/Types";
-import { makeAutoObservable, makeObservable, reaction } from "mobx";
-import { IDisposer } from "mobx-utils";
 
 export class StaticField extends Field {
 
@@ -38,9 +29,10 @@ export class StaticField extends Field {
     setContent = (newContent: string, type?: FieldContentType) => { 
         this.content = newContent;
         if (type) this.contentType = type;
+
         this.updateRenderedDoc(this.renderedDocument /*, true*/);
     };
-    getContent() { return this.content };
+    getContent() { return this.content ?? 'Unset'};
 
     applyAttributes = (field: Field) => { //!!! can be updated later for more robust clonign; this is all ythat's needed now
         super.applyAttributes(field);
@@ -98,6 +90,8 @@ export class StaticField extends Field {
                 break;
         }   
 
+        //doc[this.title] = this.content; broken for some reason
+
         this.renderedDocument = doc;
 
         return doc;
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
index 7515a39be..16e70a47b 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
@@ -9,6 +9,7 @@ import {  } from "./FieldTypes/FieldUtils";
 import { } from "./FieldTypes/StaticField";
 import { observer } from "mobx-react";
 import { IDisposer } from "mobx-utils";
+import { Width } from "../../../../../fields/DocSymbols";
 
 export class Template {
 
@@ -44,16 +45,15 @@ export class Template {
         return clone;
     }
 
-    getRenderedDoc = () => {
-        console.log('called');
-        const doc: Doc = this.doc;
-        this.contentFields.forEach(field => {
-            const title: string = field.getTitle();
-            const val: FieldType = field.getContent() as FieldType;
-            if (!title || !val) return;
-            doc[title] = val;
+    printFieldInfo = () => {
+        this.allFields.forEach(field => {
+            const doc = field.renderedDoc;
+            console.log('title: ', field.getTitle(), ' width: ', doc.width);
         });
-        return doc;
+    }
+
+    getRenderedDoc = () => {
+        return this.doc;
     }
 
     getFieldByID = (id: number): Field => {
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
index 4f1186320..bea5c2d5d 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
@@ -491,7 +491,7 @@ export class TemplateLayouts {
         tl:[0,0],
         br:[500, 600],
         opts: {
-            backgroundColor: '#DDD3A9',
+            backgroundColor: '#D7CBAB',
         },
         subfields: [
             {
@@ -502,63 +502,75 @@ export class TemplateLayouts {
                 sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL],
                 description: 'A small text field for a title that categorizes the rest of the content.',
                 opts: {
-                    borderColor: 'yellow',
-                    borderWidth: '8',
                     hCentering: "h-center",
                     backgroundColor: 'transparent',
+                    textTransform: 'uppercase',
                 },
             },
             {
                 viewType: ViewType.CAROUSEL3D,
-                tl: [-0.9, -.3],
-                br: [0.9, .9],
+                tl: [-0.9, -.5],
+                br: [0.9, .25],
                 opts: {
-                    borderColor: 'yellow',
+                    borderColor: '#847F69',
                     borderWidth: '8',
-                    backgroundColor: 'transparent',
+                    backgroundColor: '#C8BA94',
                 },
                 subfields: [
                     {
                         viewType: ViewType.STATIC,
-                        tl: [-.3, -.6],
-                        br: [.3, .6],
+                        tl: [-.4, -.6],
+                        br: [.4, .6],
                         types: [TemplateFieldType.VISUAL, TemplateFieldType.TEXT],
                         sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
                         description: 'A medium to large field for content that will share central focus with other content in the carousel.',
                         opts: {
-                            borderColor: 'yellow',
-                            borderWidth: '8',
+                            //borderColor: 'yellow',
+                            //borderWidth: '8',
                         },
                     },
                     {
                         viewType: ViewType.STATIC,
-                        tl: [-.3, -.6],
-                        br: [.3, .6],
+                        tl: [-.4, -.6],
+                        br: [.4, .6],
                         types: [TemplateFieldType.VISUAL, TemplateFieldType.TEXT],
                         sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
                         description: 'A medium to large field for content that will share central focus with other content in the carousel.',
                         opts: {
-                            borderColor: 'black',
-                            borderWidth: '8',
+                            //borderColor: 'black',
+                            //borderWidth: '8',
                         },
                     },
                     {
                         viewType: ViewType.STATIC,
-                        tl: [-.3, -.6],
-                        br: [.3, .6],
+                        tl: [-.4, -.6],
+                        br: [.4, .6],
                         types: [TemplateFieldType.VISUAL, TemplateFieldType.TEXT],
                         sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
                         description: 'A medium to large field for content that will share central focus with other content in the carousel.',
                         opts: {
-                            borderColor: 'yellow',
-                            borderWidth: '8',
+                            //borderColor: 'yellow',
+                            //borderWidth: '8',
                         },
                     },
                 ]
             },
+            {
+                viewType: ViewType.STATIC,
+                tl: [-0.9, .35],
+                br: [0.9, .9],
+                types: [TemplateFieldType.TEXT],
+                sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE],
+                description: 'A medium text field for a description of the content in the carousel.',
+                opts: {
+                    hCentering: "h-center",
+                    backgroundColor: 'transparent',
+                },
+            },
         ]
     }
 
+
     public static ThreeField001: FieldSettings = {
         title: 'threefield001',
         viewType: ViewType.FREEFORM,
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.tsx
index 413c3082e..6ab0a1774 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.tsx
@@ -2,7 +2,6 @@ import { makeAutoObservable } from "mobx";
 import { Col } from "./DocCreatorMenu";
 import { FieldSettings } from "./FieldTypes/Field";
 import { Template } from "./Template";
-import { TemplateLayouts } from "./TemplateBackend";
 
 export class TemplateManager {
 
-- 
cgit v1.2.3-70-g09d2


From fe1536918dbbca08c9900497bb466fd7aa36ffdf Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Sat, 22 Feb 2025 15:02:26 -0500
Subject: Splitting staticfield into different content types (as subclasses)

---
 src/client/views/nodes/DataVizBox/DataVizBox.tsx   |   8 +-
 .../DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx   |  10 +-
 .../DocCreatorMenu/EditableTemplateDoc.tsx         |  22 ---
 .../DocCreatorMenu/FieldTypes/DynamicField.tsx     |   3 +-
 .../DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx |  36 ++--
 .../DocCreatorMenu/FieldTypes/FieldUtils.tsx       |  14 +-
 .../DocCreatorMenu/FieldTypes/StaticContentField   |  98 ++++++++++
 .../DocCreatorMenu/FieldTypes/StaticField.tsx      | 214 ---------------------
 .../nodes/DataVizBox/DocCreatorMenu/Template.tsx   |   3 +-
 .../DataVizBox/DocCreatorMenu/TemplateBackend.tsx  |   1 -
 10 files changed, 145 insertions(+), 264 deletions(-)
 delete mode 100644 src/client/views/nodes/DataVizBox/DocCreatorMenu/EditableTemplateDoc.tsx
 create mode 100644 src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticContentField
 delete mode 100644 src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx

(limited to 'src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx')

diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
index 117311b8c..dececd1dc 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
@@ -411,10 +411,10 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
             },
             { fireImmediately: true }
         );
-        // this._disposers.contentSummary = reaction(
-        //     () => this.records,
-        //     () => this.updateGPTSummary()
-        // );
+        this._disposers.contentSummary = reaction(
+            () => this.records,
+            () => this.updateGPTSummary()
+        );
     }
 
     fetchData = () => {
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
index e8b80b7b5..b576aee82 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
@@ -32,7 +32,7 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core';
 import { TemplateFieldSize, TemplateFieldType, TemplateLayouts } from './TemplateBackend';
 import { TemplateManager } from './TemplateManager';
 import { Template } from './Template';
-import { Field, FieldContentType } from './FieldTypes/Field';
+import { Field, ViewType } from './FieldTypes/Field';
 import { TabDocView } from '../../../collections/TabDocView';
 
 export enum LayoutType {
@@ -585,7 +585,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                             const col = this.getColByTitle(colTitle);
                             if (!this._userCreatedFields.includes(col)){ // do the following for any fields not added by the user; will change in the future, for now only GPT content works with user-added fields
                                 const field = template.getFieldByID(Number(fieldID));
-                                field.setContent(col.defaultContent ?? '', col.type === TemplateFieldType.VISUAL ? FieldContentType.IMAGE : FieldContentType.STRING);
+                                field.setContent(col.defaultContent ?? '', col.type === TemplateFieldType.VISUAL ? ViewType.IMG : ViewType.TEXT);
                                 field.setTitle(col.title);
                             } else {
                                 a[Number(fieldID)] = this.getColByTitle(colTitle);
@@ -618,6 +618,8 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
         const renderedTemplates: (Template | undefined)[] = await Promise.all(renderedTemplatePromises);
 
+        templates.forEach(template => template.mainField.updateRenderedDoc())
+
         setTimeout(() => {
             this.setSuggestedTemplates(templates);
             this._GPTLoading = false;
@@ -630,7 +632,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
             console.log('url: ', url)
             const field: Field = template.getFieldByID(Number(fieldNum));
 
-            field.setContent(url ?? '', FieldContentType.IMAGE);
+            field.setContent(url ?? '', ViewType.IMG);
             field.setTitle(col.title);
         };
 
@@ -687,7 +689,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                     const field: Field = template.getFieldByID(Number(info.number));
                     const col = this.getColByTitle(title);
 
-                    field.setContent(info.content ?? '', FieldContentType.STRING);
+                    field.setContent(info.content ?? '', ViewType.TEXT);
                     field.setTitle(col.title);
                 });
             }
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/EditableTemplateDoc.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/EditableTemplateDoc.tsx
deleted file mode 100644
index 5ec27f338..000000000
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/EditableTemplateDoc.tsx
+++ /dev/null
@@ -1,22 +0,0 @@
-import { Doc } from "../../../../../fields/Doc";
-import { SubCollectionViewProps } from "../../../collections/CollectionSubView";
-import { CollectionFreeFormView } from "../../../collections/collectionFreeForm";
-import { TemplateManager } from "./TemplateManager";
-import { TemplateLayouts } from "./TemplateBackend";
-import { Template } from "./Template";
-
-class EditableTemplateDoc extends CollectionFreeFormView {
-
-    template: Template;
-
-    constructor(props: SubCollectionViewProps, template: Template){
-        super(props);
-        this.template = template;
-    }
-
-    addDocumenta = (newBox: Doc | Doc[]): boolean => {
-        this.addDocument(newBox);
-        
-        return true;
-    }
-}
\ No newline at end of file
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
index c244dd57c..2d8328ed6 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
@@ -51,8 +51,7 @@ export class DynamicField extends Field {
     };
 
     updateRenderedDoc = (): Doc => {
-        
-        //console.log('dynamic field updated');
+        console.log('dynamic field updated');
         let doc: Doc;
         const renderedSubfields: Doc[] = this.subfields.map(field => field.renderedDoc);
         switch (this.settings.viewType) {
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
index 2aa9f9032..d164053c3 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
@@ -49,7 +49,6 @@ export abstract class Field {
     get renderedDoc(){ return this.renderedDocument };
     get getDimensions() { return this.dimensions };
     get getID() { return this.id };
-    get getViewType() { return this.settings.viewType };
     get getDescription(): string { return this.settings.description ?? '' };
 
     setTitle = (title: string) => { 
@@ -58,7 +57,7 @@ export abstract class Field {
     };
     getTitle = () => { return this.title };
 
-    abstract setContent(content: string, type?: FieldContentType): void;
+    abstract setContent(content: string, type?: ViewType): void;
     abstract getContent(): string;
 
     setupFieldChangeReaction = () => {
@@ -116,7 +115,7 @@ export abstract class Field {
         this.subfields.push(newField);
     };
 
-    addField = (type?: FieldContentType) => {
+    addField = (type?: ViewType) => {
         
     }
 
@@ -142,8 +141,6 @@ export abstract class Field {
 
     abstract updateRenderedDoc(oldDoc?: Doc): void;
 
-    abstract matches(cols: Col[]): Array<number>;
-
     dispose = () => {
         Object.values(this.disposers).forEach(disposer => disposer?.());
     }
@@ -165,6 +162,26 @@ export abstract class Field {
         });
     }
 
+    matches = (cols: Col[]): number[] => {
+        const colMatchesField = (col: Col) => {
+            const isMatch: boolean = (
+                this.settings.sizes?.some(size => col.sizes?.includes(size)) 
+                && this.settings.types?.includes(col.type)) 
+                ?? false;
+            return isMatch;
+        }
+
+        const matches: Array<number> = [];
+
+        cols.forEach((col, v) => {
+            if (colMatchesField(col)) {
+                matches.push(v);
+            }
+        });
+
+        return matches;
+    };
+
 }
 
 export type FieldSettings = {
@@ -179,16 +196,13 @@ export type FieldSettings = {
     description?: string;
 };
 
-export enum FieldContentType {
-    STRING = 'string',
-    IMAGE = 'image',
-}
-
 export enum ViewType {
     CAROUSEL3D = 'carousel3d',
     FREEFORM = 'freeform',
     STATIC = 'static',
-    DEC = 'decoration'
+    DEC = 'decoration',
+    IMG = 'image',
+    TEXT = 'text',
 }
 
 export type FieldDimensions = {
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
index 27ea8e1f5..6a800b8d1 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
@@ -4,7 +4,7 @@ import { Col } from "../DocCreatorMenu";
 import { TemplateFieldSize, TemplateFieldType, TemplateLayouts } from "../TemplateBackend";
 import { DynamicField } from "./DynamicField";
 import { Field, FieldDimensions, FieldSettings, ViewType } from "./Field";
-import { StaticField } from "./StaticField";
+import { TextTemplateField, ImageTemplateField } from "./StaticContentField";
 
 export class FieldUtils {
     public static getLocalDimensions = (coords: { tl: [number, number]; br: [number, number] }, parentDimensions: FieldDimensions): FieldDimensions => {
@@ -23,9 +23,15 @@ export class FieldUtils {
     public static setupField = (settings: FieldSettings, index: number, parent: Field): Field => { 
         //console.log('settings', settings);
         const id = Number(`${parent.getID}${index}`);
-        return settings.viewType === ViewType.FREEFORM || settings.viewType === ViewType.CAROUSEL3D
-        ? new DynamicField(settings, id, parent)
-        : new StaticField(settings, parent, id); 
+        switch (settings.viewType) {
+            case ViewType.FREEFORM: case ViewType.CAROUSEL3D:
+                return new DynamicField(settings, id, parent);
+            case ViewType.IMG:
+                return new ImageTemplateField(settings, id, parent);
+            case ViewType.TEXT:
+                return new TextTemplateField(settings, id, parent);
+        }
+        return new TextTemplateField(settings, id, parent);
     }
 
     public static textProperties: string[] = [
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticContentField b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticContentField
new file mode 100644
index 000000000..da2671f9c
--- /dev/null
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticContentField
@@ -0,0 +1,98 @@
+import { Doc, DocListCast } from "../../../../../../fields/Doc";
+import { Docs, DocumentOptions } from "../../../../../documents/Documents";
+import { FieldUtils } from "./FieldUtils";
+import { Field, FieldDimensions, FieldSettings, ViewType } from "./Field";
+import { RichTextField } from "../../../../../../fields/RichTextField";
+import { DocData } from "../../../../../../fields/DocSymbols";
+import { ImageField } from "../../../../../../fields/URLField";
+
+export abstract class StaticContentField extends Field {
+
+    protected content: string; 
+    protected renderedDocument: Doc;
+    protected subfields: Field[];
+
+    protected parent: Field;
+    protected dimensions: FieldDimensions;
+
+    constructor(settings: FieldSettings, parent: Field, id: number) {
+        super(settings, id, FieldUtils.setupField, parent);
+        this.parent = parent;
+        this.dimensions = FieldUtils.getLocalDimensions({tl: settings.tl, br: settings.br}, this.parent.getDimensions);
+        this.content = '';
+        this.subfields = this.setupSubfields(this);
+        this.renderedDocument = this.updateRenderedDoc();
+    };
+
+    abstract setContent(content: string): void;
+    getContent() { return this.content ?? 'unset'};
+
+    abstract updateRenderedDoc(): Doc;
+}
+
+export class ImageTemplateField extends StaticContentField {
+
+    setContent = (url: string) => { 
+        const imgField = new ImageField(url);
+        this.renderedDocument[DocData]['data'] = imgField;
+        this.content = url;
+    };
+
+    updateRenderedDoc = (): Doc => {
+        const url = String(this.content);
+        let doc: Doc = Docs.Create.ImageDocument(url, {
+            title: this.title,
+            _layout_fitWidth: false,
+        });
+        FieldUtils.applyBasicOpts(doc, this.dimensions, this.settings);
+
+        this.renderedDocument = doc;
+
+        return doc;
+    };
+}
+
+export class TextTemplateField extends StaticContentField {
+
+    setContent = (text: string) => { 
+        const rtf = {
+            doc: {
+                type: 'doc',
+                content: [
+                    {
+                        type: 'paragraph',
+                        content: [
+                            {
+                                type: 'text',
+                                text,
+                            },
+                        ],
+                    },
+                ],
+            },
+            selection: { type: 'text', anchor: 1, head: 1 },
+            storedMarks: [],
+        };
+        this.content = text;
+        const field = new RichTextField(JSON.stringify(rtf), text);
+        this.renderedDocument[DocData]['text'] = field;
+    };
+
+    updateRenderedDoc = (): Doc => {
+        const opts = this.settings.opts;
+        const text = String(this.content);
+        let doc: Doc = Docs.Create.TextDocument(text, {
+            title: this.title,
+            text_fontColor: opts.text_fontColor,
+            contentBold: opts.contentBold,
+            textTransform: opts.textTransform,
+            color: opts.text_fontColor,
+            _text_fontSize: `${FieldUtils.calculateFontSize(this.dimensions.width, this.dimensions.height, text, true)}`
+        });
+        FieldUtils.applyBasicOpts(doc, this.dimensions, this.settings);
+
+        this.renderedDocument = doc;
+
+        return doc;
+    };
+}
\ No newline at end of file
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
deleted file mode 100644
index 2090d94b9..000000000
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
+++ /dev/null
@@ -1,214 +0,0 @@
-import { Doc, DocListCast } from "../../../../../../fields/Doc";
-import { Docs, DocumentOptions } from "../../../../../documents/Documents";
-import { Col } from "../DocCreatorMenu";
-import { FieldUtils } from "./FieldUtils";
-import { Field, FieldContentType, FieldDimensions, FieldSettings, ViewType } from "./Field";
-import { RichTextField } from "../../../../../../fields/RichTextField";
-
-export class StaticField extends Field {
-
-    private content: string;
-    private contentType: FieldContentType | undefined;
-    protected renderedDocument: Doc;
-    protected subfields: Field[];
-
-    private storedAttributes: Record<string, any>;
-
-    protected parent: Field;
-    protected dimensions: FieldDimensions;
-
-    constructor(settings: FieldSettings, parent: Field, id: number) {
-        super(settings, id, FieldUtils.setupField, parent);
-        this.parent = parent;
-        this.dimensions = FieldUtils.getLocalDimensions({tl: settings.tl, br: settings.br}, this.parent.getDimensions);
-        this.content = '';
-        this.subfields = this.setupSubfields(this);
-        this.renderedDocument = this.updateRenderedDoc();
-        this.storedAttributes = new DocumentOptions();
-    };
-
-    setContent = (newContent: string, type?: FieldContentType) => { 
-        console.log('set to: ', newContent)
-        const rtf = {
-            doc: {
-                type: 'doc',
-                content: [
-                    {
-                        type: 'paragraph',
-                        content: [
-                            {
-                                type: 'text',
-                                newContent,
-                            },
-                        ],
-                    },
-                ],
-            },
-            selection: { type: 'text', anchor: 1, head: 1 },
-            storedMarks: [],
-        };
-        const field = new RichTextField(JSON.stringify(rtf), newContent);
-        this.content = newContent;
-        // this.renderedDocument['data'] = field;
-        if (type) this.contentType = type;
-
-        this.updateRenderedDoc(this.renderedDocument /*, true*/);
-    };
-    getContent() { return this.content ?? 'Unset'};
-
-    applyAttributes = (field: Field) => { //!!! can be updated later for more robust clonign; this is all ythat's needed now
-        super.applyAttributes(field);
-        field.setContent('', this.contentType);
-    }
-
-    matches = (cols: Col[]): number[] => {
-        const colMatchesField = (col: Col) => {
-            const isMatch: boolean = (
-                this.settings.sizes?.some(size => col.sizes?.includes(size)) 
-                && this.settings.types?.includes(col.type)) 
-                ?? false;
-            return isMatch;
-        }
-
-        const matches: Array<number> = [];
-
-        cols.forEach((col, v) => {
-            if (colMatchesField(col)) {
-                matches.push(v);
-            }
-        });
-
-        return matches;
-    };
-
-    updateRenderedDoc = (oldDoc?: Doc): Doc => {
-        const opts = this.settings.opts;
-
-        if (!this.contentType) { this.contentType = FieldContentType.STRING };
-
-        let doc: Doc;
-
-        switch (this.contentType) {
-            case FieldContentType.STRING:
-                const text = String(this.content);
-                console.log('creating text doc with text: ', text)
-                doc = Docs.Create.TextDocument(text, {
-                    title: this.title,
-                    text_fontColor: oldDoc ? String(oldDoc.color) : opts.text_fontColor,
-                    contentBold: oldDoc ? Boolean(oldDoc.fontBold) : opts.contentBold,
-                    textTransform: oldDoc ? String(oldDoc.fontTransform) : opts.textTransform,
-                    color: oldDoc ? String(oldDoc.color) : opts.text_fontColor,
-                    _text_fontSize: `${FieldUtils.calculateFontSize(this.dimensions.width, this.dimensions.height, text, true)}`
-                });
-                FieldUtils.applyBasicOpts(doc, this.dimensions, this.settings, oldDoc);
-                break;
-            case FieldContentType.IMAGE:
-                const url = String(this.content);
-                doc = Docs.Create.ImageDocument(url, {
-                    title: this.title,
-                    _layout_fitWidth: false,
-                });
-                FieldUtils.applyBasicOpts(doc, this.dimensions, this.settings, oldDoc);
-                break;
-        }   
-
-        //doc[this.title] = this.content; broken for some reason
-
-        this.renderedDocument = doc;
-
-        return doc;
-    };
-
-    // updateRenderedDoc = (currDoc?: Doc, forceRerender?: boolean) => {
-
-    //     if (!this.contentType) { this.contentType = FieldContentType.STRING };
-
-    //     let doc: Doc;
-
-    //     // if (this.shouldRerender() || forceRerender) {
-    //     // } else {
-    //     //     this.updateStoredAttributes(this.renderedDocument);
-    //     // }
-
-    //     this.updateStoredAttributes(this.renderedDocument);
-
-    //     let list: string[] = Object.entries(this.storedAttributes).map(([key, value]) => `${key}: ${value}`);
-    //     console.log(list);
-
-    //         switch (this.contentType) {
-    //             case FieldContentType.STRING:
-    //                 const text = String(this.content);
-    //                 this.storedAttributes._text_fontSize = `${FieldUtils.calculateFontSize(this.dimensions.width, this.dimensions.height, this.content, true)}`
-    //                 doc = Docs.Create.TextDocument(text, this.storedAttributes);
-    //                 break;
-    //             case FieldContentType.IMAGE:
-    //                 const url = String(this.content);
-    //                 doc = Docs.Create.ImageDocument(url, this.storedAttributes);
-    //                 break;
-    //         } 
-    //         doc._layout_hideScroll = true;  
-
-
-    //         console.log(StrCast(doc.backgroundColor), StrCast(doc._rotation));
-
-    //         this.renderedDocument = doc;
-
-    //     //this.renderedDocument = doc;
-    // };
-
-    // private updateStoredAttributes = (currDoc?: Doc) => {
-    //     const opts = this.settings.opts;
-    //     console.log("num atts", Object.entries(this.storedAttributes).length);
-    //     Object.entries(this.storedAttributes).forEach(([key, value]) => {
-    //         key = String(key); 
-    //         if (currDoc && currDoc[key] !== undefined) {
-    //             this.storedAttributes[key] = currDoc[key];
-    //         } else if (opts[key as keyof typeof opts] !== undefined) {
-    //             this.storedAttributes[key] = opts[key as keyof typeof opts];
-    //         }
-    //     });
-    // }
-
-    // private shouldRerender = (): boolean => {
-    //     return FieldUtils.textProperties.some(property => 
-    //         this.renderedDocument[property] !== this.storedAttributes[property]
-    //     );
-    // };
-
-    private setupRenderedDoc = (): Doc => {
-        const docOptions: Record<string, any> = new DocumentOptions();
-
-        docOptions.isDefaultTemplateDoc = true;
-        docOptions.x = this.dimensions.coord.x;
-        docOptions.y = this.dimensions.coord.y;
-        docOptions._height = this.dimensions.height;
-        docOptions._width = this.dimensions.width;
-        docOptions._nativeWidth = this.dimensions.width;
-        docOptions._nativeHeight = this.dimensions.height;
-
-        Object.entries(this.settings.opts).forEach(([key, value]) => {
-            docOptions[key] = value;
-        });
-
-        let doc: Doc;
-        switch (this.contentType) {
-            case FieldContentType.STRING:
-                doc = Docs.Create.TextDocument(this.content, docOptions);
-                break;
-            case FieldContentType.IMAGE:
-                doc = Docs.Create.ImageDocument(this.content, docOptions);
-                break;
-            default:
-                doc = Docs.Create.TextDocument(this.content, docOptions);
-                break;
-        }  
-
-        doc._layout_hideScroll = true;
-        //doc._layout_borderRounding = !opts._layout_borderRounding ? '0px' : ScriptField.MakeFunction(`${opts._layout_borderRounding} * this.width + 'px'`);
-
-        this.renderedDocument = doc;
-
-        return doc;
-        }
-
-}
\ No newline at end of file
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
index 16e70a47b..9d132d637 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
@@ -6,7 +6,6 @@ import { Col } from "./DocCreatorMenu";
 import { DynamicField } from "./FieldTypes/DynamicField";
 import { Field, FieldSettings, ViewType } from "./FieldTypes/Field";
 import {  } from "./FieldTypes/FieldUtils";
-import { } from "./FieldTypes/StaticField";
 import { observer } from "mobx-react";
 import { IDisposer } from "mobx-utils";
 import { Width } from "../../../../../fields/DocSymbols";
@@ -25,7 +24,7 @@ export class Template {
 
     get childFields(): Field[] { return this.mainField.getSubfields };
     get allFields(): Field[] { return this.mainField.getAllSubfields };
-    get contentFields(): Field[] { return this.allFields.filter(field => field.getViewType === ViewType.STATIC) };
+    get contentFields(): Field[] { return this.allFields.filter(field => field !instanceof DynamicField) };
     get doc(){ return this.mainField.renderedDoc; };
     get title() { return this.mainField.getTitle() };
 
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
index bea5c2d5d..583b2f472 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
@@ -1,5 +1,4 @@
 import { FieldOpts, FieldSettings, ViewType } from "./FieldTypes/Field";
-import { } from "./FieldTypes/StaticField";
 
 export enum TemplateFieldType {
     TEXT = 'text',
-- 
cgit v1.2.3-70-g09d2


From 3b98831182a4d830cf577fa217a477b2cadcd7bc Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Wed, 26 Feb 2025 16:27:10 -0500
Subject: separated field content classes technically working

---
 .../DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx   |  12 ++-
 .../DocCreatorMenu/FieldTypes/DecorationField.tsx  |  38 +++++++
 .../DocCreatorMenu/FieldTypes/DynamicField.tsx     |  11 ++-
 .../DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx |  19 ++--
 .../DocCreatorMenu/FieldTypes/FieldUtils.tsx       |  12 ++-
 .../DocCreatorMenu/FieldTypes/StaticContentField   |  98 ------------------
 .../FieldTypes/StaticContentField.tsx              | 109 +++++++++++++++++++++
 .../nodes/DataVizBox/DocCreatorMenu/Template.tsx   |   8 +-
 .../DataVizBox/DocCreatorMenu/TemplateManager.tsx  |   2 +-
 9 files changed, 183 insertions(+), 126 deletions(-)
 create mode 100644 src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DecorationField.tsx
 delete mode 100644 src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticContentField
 create mode 100644 src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticContentField.tsx

(limited to 'src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx')

diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
index b576aee82..6f3647133 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
@@ -568,13 +568,17 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
         let prompt: string = `(${origCount}) ${inputText}`;
 
+        console.log('prompt is: ', prompt)
+
         this._GPTLoading = true;
 
         try {
             const res = await gptAPICall(prompt, GPTCallType.TEMPLATE);
 
             if (res) {
+                console.log('res is: ', res)
                 const assignments: { [templateTitle: string]: { [fieldID: string]: string } } = JSON.parse(res);
+                console.log('assignments: ', assignments)
                 const brokenDownAssignments: [Template, { [fieldID: number]: Col }][] = [];
 
                 Object.entries(assignments).forEach(([tempTitle, assignment]) => {
@@ -583,7 +587,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                     const toObj = Object.entries(assignment).reduce(
                         (a, [fieldID, colTitle]) => {
                             const col = this.getColByTitle(colTitle);
-                            if (!this._userCreatedFields.includes(col)){ // do the following for any fields not added by the user; will change in the future, for now only GPT content works with user-added fields
+                            if (!this._userCreatedFields.includes(col)){ // do the following for any fields not added by the user; will change in the future, for now only GPT content works with user-added field
                                 const field = template.getFieldByID(Number(fieldID));
                                 field.setContent(col.defaultContent ?? '', col.type === TemplateFieldType.VISUAL ? ViewType.IMG : ViewType.TEXT);
                                 field.setTitle(col.title);
@@ -594,7 +598,9 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                         },
                         {} as { [field: number]: Col }
                     );
+                    console.log('all assignments: ', toObj)
                     brokenDownAssignments.push([template, toObj]);
+                    console.log('brokendownassignments: ', brokenDownAssignments)
                 });
 
                 return brokenDownAssignments;
@@ -612,13 +618,15 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         const cols = this.fieldsInfos;
         const templates = this.templateManager.getValidTemplates(cols);
 
+        console.log(templates)
+
         const assignments: [Template, { [field: number]: Col }][] = await this.assignColsToFields(templates, cols);
 
         const renderedTemplatePromises: Promise<Template | undefined>[] = assignments.map(([template, assignments]) => this.applyGPTContentToTemplate(template, assignments));
 
         const renderedTemplates: (Template | undefined)[] = await Promise.all(renderedTemplatePromises);
 
-        templates.forEach(template => template.mainField.updateRenderedDoc())
+        templates.forEach(template => template.mainField.initRenderedDoc())
 
         setTimeout(() => {
             this.setSuggestedTemplates(templates);
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DecorationField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DecorationField.tsx
new file mode 100644
index 000000000..efe398aaa
--- /dev/null
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DecorationField.tsx
@@ -0,0 +1,38 @@
+import { Doc, DocListCast } from "../../../../../../fields/Doc";
+import { Docs, DocumentOptions } from "../../../../../documents/Documents";
+import { FieldUtils } from "./FieldUtils";
+import { Field, FieldDimensions, FieldSettings, ViewType } from "./Field";
+import { RichTextField } from "../../../../../../fields/RichTextField";
+import { DocData } from "../../../../../../fields/DocSymbols";
+import { ImageField } from "../../../../../../fields/URLField";
+
+export class DecorationField extends Field {
+
+    protected content: string = ''; 
+    protected subfields: Field[];
+
+    protected renderedDocument: Doc;
+
+    protected dimensions: FieldDimensions;
+
+    constructor(settings: FieldSettings, parent: Field, id: number) {
+        super(settings, id, FieldUtils.initField, parent);
+        this.dimensions = FieldUtils.getLocalDimensions({tl: settings.tl, br: settings.br}, this.parent.getDimensions);
+        this.subfields = this.setupSubfields(this);
+        this.renderedDocument = this.initRenderedDoc();
+    };
+
+    setContent = (content: string, type?: ViewType) => { return }
+    getContent = () => { return 'none'};
+    get isContentField(): boolean { return false };
+
+    initRenderedDoc = (): Doc => {
+        const renderedSubfields: Doc[] = this.subfields.map(field => field.renderedDoc);
+        let doc: Doc = Docs.Create.FreeformDocument(renderedSubfields, { title: this.title, });
+        FieldUtils.applyBasicOpts(doc, this.dimensions, this.settings);
+
+        this.renderedDocument = doc;
+
+        return doc;
+    };
+}
\ No newline at end of file
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
index 2d8328ed6..e5f080645 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
@@ -1,7 +1,7 @@
 import { Doc, DocListCast } from "../../../../../../fields/Doc";
 import { Docs } from "../../../../../documents/Documents";
 import { Col } from "../DocCreatorMenu";
-import { Field, FieldContentType, FieldDimensions, FieldSettings, ViewType } from "./Field";
+import { Field, FieldDimensions, FieldSettings, ViewType } from "./Field";
 import { FieldUtils } from "./FieldUtils";
 
 export class DynamicField extends Field {
@@ -12,7 +12,7 @@ export class DynamicField extends Field {
     protected renderedDocument: Doc;
 
     constructor(settings: FieldSettings, id: number, parent?: Field) {
-        super(settings, id, FieldUtils.setupField, parent);
+        super(settings, id, FieldUtils.initField, parent);
         if (!parent) {
             this.parent = this;
             this.dimensions = {width: this.settings.br[0] - this.settings.tl[0], height: this.settings.br[1] - this.settings.tl[1], coord: {x: this.settings.tl[0], y: this.settings.tl[1]}};
@@ -22,7 +22,7 @@ export class DynamicField extends Field {
         }
         //console.log('new field dimensions: ', this.dimensions);
         this.subfields = this.setupSubfields(this);
-        this.renderedDocument = this.updateRenderedDoc(); //!!!
+        this.renderedDocument = this.initRenderedDoc(); //!!!
 
         // this.disposers.fieldList = reaction(
         //     () => DocListCast(this.doc[Doc.LayoutFieldKey(this.doc)]),
@@ -32,8 +32,9 @@ export class DynamicField extends Field {
         // );
     }
 
-    setContent = (content: string, type?: FieldContentType) => { return };
+    setContent = (content: string, type?: ViewType) => { return };
     getContent = () => { return '' };
+    get isContentField(): boolean { return false };
 
     matches = (cols: Col[]): Array<number> => {
         return [];
@@ -50,7 +51,7 @@ export class DynamicField extends Field {
         return { width, height, coord };
     };
 
-    updateRenderedDoc = (): Doc => {
+    initRenderedDoc = (): Doc => {
         console.log('dynamic field updated');
         let doc: Doc;
         const renderedSubfields: Doc[] = this.subfields.map(field => field.renderedDoc);
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
index d164053c3..9427d6c5c 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
@@ -8,13 +8,13 @@ import { DocumentType } from "../../../../../documents/DocumentTypes";
 export abstract class Field {
 
     protected disposers: { [name: string]: IDisposer } = {};
-    private setupField: (settings: FieldSettings, index: number, parent: Field) => Field;
+    private initField: (settings: FieldSettings, index: number, parent: Field) => Field;
 
     protected abstract subfields: Field[];
 
     protected abstract renderedDocument: Doc;
 
-    protected parent?: Field;
+    protected parent: Field;
     protected id: number;
     protected settings: FieldSettings;
     protected title: string = '';
@@ -22,7 +22,7 @@ export abstract class Field {
     protected abstract dimensions: FieldDimensions;
 
     constructor(settings: FieldSettings, id: number, fieldFactory: (settings: FieldSettings, index: number, parent: Field) => Field, parent?: Field) {
-        this.setupField = fieldFactory;
+        this.initField = fieldFactory;
         this.parent = parent ? parent : this;
         this.id = id;
         this.settings = settings;
@@ -57,6 +57,7 @@ export abstract class Field {
     };
     getTitle = () => { return this.title };
 
+    abstract get isContentField(): boolean;
     abstract setContent(content: string, type?: ViewType): void;
     abstract getContent(): string;
 
@@ -111,7 +112,7 @@ export abstract class Field {
             }
         });
         
-        const newField: Field = this.setupField(settings, this.subfields.length, this);
+        const newField: Field = this.initField(settings, this.subfields.length, this);
         this.subfields.push(newField);
     };
 
@@ -126,27 +127,23 @@ export abstract class Field {
 
     setupSubfields = (parent: Field): Field[] => {
         return this.settings.subfields?.map((fieldSettings, index) => {
-            return this.setupField(fieldSettings, index, parent);
+            return this.initField(fieldSettings, index, parent);
         }) || [];
     }
 
     applyAttributes(field: Field) {
         field.setTitle(this.title);
-        //this.updateRenderedDoc(this.renderedDoc);
-        field.updateRenderedDoc(this.renderedDoc);
+        field.initRenderedDoc(this.renderedDoc);
         field.subfields = this.subfields;
-        //console.log('id:', this.id, 'set width to:', Number(this.renderedDoc.width));
-        //console.log('set height to:', Number(this.renderedDoc.height));
     }
 
-    abstract updateRenderedDoc(oldDoc?: Doc): void;
+    abstract initRenderedDoc(oldDoc?: Doc): void;
 
     dispose = () => {
         Object.values(this.disposers).forEach(disposer => disposer?.());
     }
 
     handleFieldUpdate = (newDocsList: Doc[]) => {
-        console.log('handlefielduodate called');
         const currRenderedDocs: Set<Doc> = new Set();
         this.subfields.forEach(field => currRenderedDocs.add(field.renderedDoc));
         newDocsList.forEach(doc => {
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
index 6a800b8d1..d7cf24794 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
@@ -5,6 +5,7 @@ import { TemplateFieldSize, TemplateFieldType, TemplateLayouts } from "../Templa
 import { DynamicField } from "./DynamicField";
 import { Field, FieldDimensions, FieldSettings, ViewType } from "./Field";
 import { TextTemplateField, ImageTemplateField } from "./StaticContentField";
+import { DecorationField } from "./DecorationField";
 
 export class FieldUtils {
     public static getLocalDimensions = (coords: { tl: [number, number]; br: [number, number] }, parentDimensions: FieldDimensions): FieldDimensions => {
@@ -20,18 +21,19 @@ export class FieldUtils {
         return { width, height, coord };
     };
 
-    public static setupField = (settings: FieldSettings, index: number, parent: Field): Field => { 
-        //console.log('settings', settings);
+    public static initField = (settings: FieldSettings, index: number, parent: Field): Field => { 
         const id = Number(`${parent.getID}${index}`);
         switch (settings.viewType) {
             case ViewType.FREEFORM: case ViewType.CAROUSEL3D:
                 return new DynamicField(settings, id, parent);
             case ViewType.IMG:
-                return new ImageTemplateField(settings, id, parent);
+                return new ImageTemplateField(settings, parent, id);
             case ViewType.TEXT:
-                return new TextTemplateField(settings, id, parent);
+                return new TextTemplateField(settings, parent, id);
+            case ViewType.DEC:
+                return new DecorationField(settings, parent, id);
         }
-        return new TextTemplateField(settings, id, parent);
+        return new TextTemplateField(settings, parent, id);
     }
 
     public static textProperties: string[] = [
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticContentField b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticContentField
deleted file mode 100644
index da2671f9c..000000000
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticContentField
+++ /dev/null
@@ -1,98 +0,0 @@
-import { Doc, DocListCast } from "../../../../../../fields/Doc";
-import { Docs, DocumentOptions } from "../../../../../documents/Documents";
-import { FieldUtils } from "./FieldUtils";
-import { Field, FieldDimensions, FieldSettings, ViewType } from "./Field";
-import { RichTextField } from "../../../../../../fields/RichTextField";
-import { DocData } from "../../../../../../fields/DocSymbols";
-import { ImageField } from "../../../../../../fields/URLField";
-
-export abstract class StaticContentField extends Field {
-
-    protected content: string; 
-    protected renderedDocument: Doc;
-    protected subfields: Field[];
-
-    protected parent: Field;
-    protected dimensions: FieldDimensions;
-
-    constructor(settings: FieldSettings, parent: Field, id: number) {
-        super(settings, id, FieldUtils.setupField, parent);
-        this.parent = parent;
-        this.dimensions = FieldUtils.getLocalDimensions({tl: settings.tl, br: settings.br}, this.parent.getDimensions);
-        this.content = '';
-        this.subfields = this.setupSubfields(this);
-        this.renderedDocument = this.updateRenderedDoc();
-    };
-
-    abstract setContent(content: string): void;
-    getContent() { return this.content ?? 'unset'};
-
-    abstract updateRenderedDoc(): Doc;
-}
-
-export class ImageTemplateField extends StaticContentField {
-
-    setContent = (url: string) => { 
-        const imgField = new ImageField(url);
-        this.renderedDocument[DocData]['data'] = imgField;
-        this.content = url;
-    };
-
-    updateRenderedDoc = (): Doc => {
-        const url = String(this.content);
-        let doc: Doc = Docs.Create.ImageDocument(url, {
-            title: this.title,
-            _layout_fitWidth: false,
-        });
-        FieldUtils.applyBasicOpts(doc, this.dimensions, this.settings);
-
-        this.renderedDocument = doc;
-
-        return doc;
-    };
-}
-
-export class TextTemplateField extends StaticContentField {
-
-    setContent = (text: string) => { 
-        const rtf = {
-            doc: {
-                type: 'doc',
-                content: [
-                    {
-                        type: 'paragraph',
-                        content: [
-                            {
-                                type: 'text',
-                                text,
-                            },
-                        ],
-                    },
-                ],
-            },
-            selection: { type: 'text', anchor: 1, head: 1 },
-            storedMarks: [],
-        };
-        this.content = text;
-        const field = new RichTextField(JSON.stringify(rtf), text);
-        this.renderedDocument[DocData]['text'] = field;
-    };
-
-    updateRenderedDoc = (): Doc => {
-        const opts = this.settings.opts;
-        const text = String(this.content);
-        let doc: Doc = Docs.Create.TextDocument(text, {
-            title: this.title,
-            text_fontColor: opts.text_fontColor,
-            contentBold: opts.contentBold,
-            textTransform: opts.textTransform,
-            color: opts.text_fontColor,
-            _text_fontSize: `${FieldUtils.calculateFontSize(this.dimensions.width, this.dimensions.height, text, true)}`
-        });
-        FieldUtils.applyBasicOpts(doc, this.dimensions, this.settings);
-
-        this.renderedDocument = doc;
-
-        return doc;
-    };
-}
\ No newline at end of file
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticContentField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticContentField.tsx
new file mode 100644
index 000000000..baa5e71ec
--- /dev/null
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticContentField.tsx
@@ -0,0 +1,109 @@
+import { Doc, DocListCast } from "../../../../../../fields/Doc";
+import { Docs, DocumentOptions } from "../../../../../documents/Documents";
+import { FieldUtils } from "./FieldUtils";
+import { Field, FieldDimensions, FieldSettings, ViewType } from "./Field";
+import { RichTextField } from "../../../../../../fields/RichTextField";
+import { DocData } from "../../../../../../fields/DocSymbols";
+import { ImageField } from "../../../../../../fields/URLField";
+
+export abstract class StaticContentField extends Field {
+
+    protected content: string = ''; 
+    protected subfields: Field[];
+
+    protected dimensions: FieldDimensions;
+
+    constructor(settings: FieldSettings, parent: Field, id: number) {
+        super(settings, id, FieldUtils.initField, parent);
+        this.dimensions = FieldUtils.getLocalDimensions({tl: settings.tl, br: settings.br}, this.parent.getDimensions);
+        this.subfields = this.setupSubfields(this);
+    };
+
+    abstract setContent(content: string, type?: ViewType): void;
+    getContent = () => { return this.content ?? 'unset'};
+    get isContentField(): boolean { return true };
+
+    abstract initRenderedDoc(): Doc;
+}
+
+export class ImageTemplateField extends StaticContentField {
+
+    protected renderedDocument: Doc;
+
+    constructor(settings: FieldSettings, parent: Field, id: number){
+        super(settings, parent, id)
+        this.renderedDocument = this.initRenderedDoc();
+    }
+
+    setContent = (url: string, type?: ViewType) => { 
+        const imgField = new ImageField(url);
+        this.renderedDocument[DocData]['data'] = imgField;
+        this.content = url;
+    };
+
+    initRenderedDoc = (): Doc => {
+        const url = String(this.content);
+        let doc: Doc = Docs.Create.ImageDocument(url, {
+            title: this.title,
+            _layout_fitWidth: false,
+        });
+        FieldUtils.applyBasicOpts(doc, this.dimensions, this.settings);
+
+        this.renderedDocument = doc;
+
+        return doc;
+    };
+}
+
+export class TextTemplateField extends StaticContentField {
+
+    protected renderedDocument: Doc;
+
+    constructor(settings: FieldSettings, parent: Field, id: number){
+        super(settings, parent, id)
+        this.renderedDocument = this.initRenderedDoc();
+    }
+
+    setContent = (text: string) => { 
+        console.log('content set to: ', text);
+        const rtf = {
+            doc: {
+                type: 'doc',
+                content: [
+                    {
+                        type: 'paragraph',
+                        content: [
+                            {
+                                type: 'text',
+                                text,
+                            },
+                        ],
+                    },
+                ],
+            },
+            selection: { type: 'text', anchor: 1, head: 1 },
+            storedMarks: [],
+        };
+        this.content = text;
+        const field = new RichTextField(JSON.stringify(rtf), text);
+        this.renderedDocument[DocData]['text'] = field;
+    };
+
+    initRenderedDoc = (): Doc => {
+        const opts = this.settings.opts;
+        const text = String(this.content);
+        let doc: Doc = Docs.Create.TextDocument(text, {
+            title: this.title,
+            text_fontColor: opts.text_fontColor,
+            contentBold: opts.contentBold,
+            textTransform: opts.textTransform,
+            color: opts.text_fontColor,
+            _text_fontSize: `${FieldUtils.calculateFontSize(this.dimensions.width, this.dimensions.height, text, true)}`
+        });
+        FieldUtils.applyBasicOpts(doc, this.dimensions, this.settings);
+
+        this.renderedDocument = doc;
+
+        return doc;
+    };
+}
\ No newline at end of file
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
index 9d132d637..178af3df6 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
@@ -24,7 +24,7 @@ export class Template {
 
     get childFields(): Field[] { return this.mainField.getSubfields };
     get allFields(): Field[] { return this.mainField.getAllSubfields };
-    get contentFields(): Field[] { return this.allFields.filter(field => field !instanceof DynamicField) };
+    get contentFields(): Field[] { return this.allFields.filter(field => field.isContentField) };
     get doc(){ return this.mainField.renderedDoc; };
     get title() { return this.mainField.getTitle() };
 
@@ -36,11 +36,10 @@ export class Template {
         const clone: Template = new Template(this.settings);
         this.mainField.applyAttributes(clone.mainField);
         clone.allFields.filter(field => field !== clone.mainField).forEach(field => {
-            console.log('id:', field.getID);
             const matchingField: Field = this.allFields.filter(f => f.getID === field.getID)[0];
             matchingField.applyAttributes(field);
         })
-        clone.mainField.updateRenderedDoc();
+        clone.mainField.initRenderedDoc();
         return clone;
     }
 
@@ -85,13 +84,14 @@ export class Template {
 
     resetToBase = () => {
         this.allFields.forEach(field => {
-            field.updateRenderedDoc();
+            field.initRenderedDoc();
         })
     }
 
     isValidTemplate = (cols: Col[]) => {
         const matches: number[][] = this.getMatches(cols);
         const maxMatches: number = this.maxMatches(matches);
+        console.log('title: ', this.mainField.getTitle(), ' matches: ', matches, ' max: ', maxMatches, ' num content fields: ', this.contentFields.length)
         return maxMatches === this.contentFields.length;
     }
 
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.tsx
index 6ab0a1774..09b4ce029 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.tsx
@@ -6,7 +6,6 @@ import { Template } from "./Template";
 export class TemplateManager {
 
     templates: Template[] = [];
-    //updateTrack
 
     constructor(templateSettings: FieldSettings[]) {
         makeAutoObservable(this);
@@ -20,6 +19,7 @@ export class TemplateManager {
     }
 
     getValidTemplates = (cols: Col[]): Template[] => {
+        console.log('called in manager with templates: ', this.templates)
         return this.templates.filter(template => template.isValidTemplate(cols));
     }
 
-- 
cgit v1.2.3-70-g09d2


From b623446ec0e71a3f696d14c3f169781c99f7e7b7 Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Wed, 26 Feb 2025 17:01:41 -0500
Subject: field type changing works

---
 .../DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx   | 14 ++---
 .../DocCreatorMenu/FieldTypes/DynamicField.tsx     |  2 +-
 .../DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx | 14 ++++-
 .../FieldTypes/StaticContentField.tsx              | 66 +++++++++++++---------
 .../nodes/DataVizBox/DocCreatorMenu/Template.tsx   |  1 -
 5 files changed, 56 insertions(+), 41 deletions(-)

(limited to 'src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx')

diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
index 6f3647133..faa6cffa8 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
@@ -568,17 +568,13 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
         let prompt: string = `(${origCount}) ${inputText}`;
 
-        console.log('prompt is: ', prompt)
-
         this._GPTLoading = true;
 
         try {
             const res = await gptAPICall(prompt, GPTCallType.TEMPLATE);
 
             if (res) {
-                console.log('res is: ', res)
                 const assignments: { [templateTitle: string]: { [fieldID: string]: string } } = JSON.parse(res);
-                console.log('assignments: ', assignments)
                 const brokenDownAssignments: [Template, { [fieldID: number]: Col }][] = [];
 
                 Object.entries(assignments).forEach(([tempTitle, assignment]) => {
@@ -598,9 +594,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                         },
                         {} as { [field: number]: Col }
                     );
-                    console.log('all assignments: ', toObj)
                     brokenDownAssignments.push([template, toObj]);
-                    console.log('brokendownassignments: ', brokenDownAssignments)
                 });
 
                 return brokenDownAssignments;
@@ -733,14 +727,14 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
             fields.filter(title => title).forEach(title => {
                 const field = templateCopy.getFieldByTitle(title);
-                if (field === undefined) { return };
-                field.setContent(content[title]);
+                if (field === undefined) return;
+                field.setContent(content[title], field.viewType);
             });
     
             const gptPromises = this._userCreatedFields.filter(field => field.type === TemplateFieldType.TEXT).map(field => {
                 const title = field.title;
                 const templateField = templateCopy.getFieldByTitle(title);
-                if (templateField === undefined) { return };
+                if (templateField === undefined) return;
                 const templatefieldID = templateField.getID;
     
                 return this.renderGPTTextCall(templateCopy, field, templatefieldID);
@@ -749,7 +743,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
             const imagePromises = this._userCreatedFields.filter(field => field.type === TemplateFieldType.VISUAL).map(field => {
                 const title = field.title;
                 const templateField = templateCopy.getFieldByTitle(title);
-                if (templateField === undefined) { return };
+                if (templateField === undefined) return;
                 const templatefieldID = templateField.getID;
     
                 return this.renderGPTImageCall(templateCopy, field, templatefieldID);
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
index e5f080645..7ffb1884e 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
@@ -32,7 +32,7 @@ export class DynamicField extends Field {
         // );
     }
 
-    setContent = (content: string, type?: ViewType) => { return };
+    setContent = (content: string, type: ViewType) => { return };
     getContent = () => { return '' };
     get isContentField(): boolean { return false };
 
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
index 9427d6c5c..6c78e15ad 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
@@ -50,6 +50,7 @@ export abstract class Field {
     get getDimensions() { return this.dimensions };
     get getID() { return this.id };
     get getDescription(): string { return this.settings.description ?? '' };
+    get viewType(): ViewType { return this.settings.viewType }
 
     setTitle = (title: string) => { 
         this.title = title;
@@ -58,9 +59,20 @@ export abstract class Field {
     getTitle = () => { return this.title };
 
     abstract get isContentField(): boolean;
-    abstract setContent(content: string, type?: ViewType): void;
+    abstract setContent(content: string, type: ViewType): void;
     abstract getContent(): string;
 
+    changeFieldType = (newType: ViewType): Field => {
+        this.settings.viewType = newType;
+        const newField: Field = this.initField(this.settings, this.id, this.parent);
+        this.parent.exchangeFields(newField, this);
+        return newField;
+    }
+
+    exchangeFields = (newField: Field, oldField: Field) => {
+        this.subfields.splice(this.subfields.indexOf(oldField), 1, newField);
+    }
+
     setupFieldChangeReaction = () => {
 
     }
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticContentField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticContentField.tsx
index baa5e71ec..627d3a939 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticContentField.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticContentField.tsx
@@ -5,6 +5,7 @@ import { Field, FieldDimensions, FieldSettings, ViewType } from "./Field";
 import { RichTextField } from "../../../../../../fields/RichTextField";
 import { DocData } from "../../../../../../fields/DocSymbols";
 import { ImageField } from "../../../../../../fields/URLField";
+import { ViewComponentType } from "@fullcalendar/core";
 
 export abstract class StaticContentField extends Field {
 
@@ -19,7 +20,7 @@ export abstract class StaticContentField extends Field {
         this.subfields = this.setupSubfields(this);
     };
 
-    abstract setContent(content: string, type?: ViewType): void;
+    abstract setContent(content: string, type: ViewType): void;
     getContent = () => { return this.content ?? 'unset'};
     get isContentField(): boolean { return true };
 
@@ -35,10 +36,15 @@ export class ImageTemplateField extends StaticContentField {
         this.renderedDocument = this.initRenderedDoc();
     }
 
-    setContent = (url: string, type?: ViewType) => { 
-        const imgField = new ImageField(url);
-        this.renderedDocument[DocData]['data'] = imgField;
-        this.content = url;
+    setContent = (url: string, type: ViewType) => { 
+        if (type === ViewType.IMG){
+            const imgField = new ImageField(url);
+            this.renderedDocument[DocData]['data'] = imgField;
+            this.content = url;
+        } else {
+            const updatedField = this.changeFieldType(type);
+            updatedField.setContent(url, type);
+        }
     };
 
     initRenderedDoc = (): Doc => {
@@ -64,29 +70,33 @@ export class TextTemplateField extends StaticContentField {
         this.renderedDocument = this.initRenderedDoc();
     }
 
-    setContent = (text: string) => { 
-        console.log('content set to: ', text);
-        const rtf = {
-            doc: {
-                type: 'doc',
-                content: [
-                    {
-                        type: 'paragraph',
-                        content: [
-                            {
-                                type: 'text',
-                                text,
-                            },
-                        ],
-                    },
-                ],
-            },
-            selection: { type: 'text', anchor: 1, head: 1 },
-            storedMarks: [],
-        };
-        this.content = text;
-        const field = new RichTextField(JSON.stringify(rtf), text);
-        this.renderedDocument[DocData]['text'] = field;
+    setContent = (text: string, type: ViewType) => { 
+        if (type === ViewType.TEXT) {
+            const rtf = {
+                doc: {
+                    type: 'doc',
+                    content: [
+                        {
+                            type: 'paragraph',
+                            content: [
+                                {
+                                    type: 'text',
+                                    text,
+                                },
+                            ],
+                        },
+                    ],
+                },
+                selection: { type: 'text', anchor: 1, head: 1 },
+                storedMarks: [],
+            };
+            this.content = text;
+            const field = new RichTextField(JSON.stringify(rtf), text);
+            this.renderedDocument[DocData]['text'] = field;
+        } else {
+            const updatedField = this.changeFieldType(type);
+            updatedField.setContent(text, type);
+        }
     };
 
     initRenderedDoc = (): Doc => {
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
index 178af3df6..a80df8468 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
@@ -19,7 +19,6 @@ export class Template {
         makeAutoObservable(this);
         this.settings = templateInfo;
         this.mainField = this.setupMainField(templateInfo);
-        console.log(templateInfo);
     }
 
     get childFields(): Field[] { return this.mainField.getSubfields };
-- 
cgit v1.2.3-70-g09d2


From 7d9fae09e8906e5636f6ea695ad560797b08d023 Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Wed, 26 Feb 2025 21:11:36 -0500
Subject: something broke, reverting

---
 src/client/documents/Documents.ts                  |  1 +
 .../DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx   | 20 +++++++-------------
 .../DocCreatorMenu/FieldTypes/DynamicField.tsx     |  5 +++--
 .../DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx | 12 ++++++++----
 .../DocCreatorMenu/FieldTypes/FieldUtils.tsx       |  2 +-
 .../FieldTypes/StaticContentField.tsx              | 22 +++++++++++++++-------
 .../nodes/DataVizBox/DocCreatorMenu/Template.tsx   |  1 -
 7 files changed, 35 insertions(+), 28 deletions(-)

(limited to 'src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx')

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 0a7047128..033a5e9be 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -704,6 +704,7 @@ export namespace Docs {
             }
 
             // users placeholderDoc as proto if it exists
+            console.log('placeholder: ', placeholderDocIn, ' data: ', dataProps['data'])
             const dataDoc = Doc.assign(placeholderDoc ? Doc.GetProto(placeholderDoc) : Doc.MakeDelegate(proto, protoId), dataProps, undefined, true);
 
             if (placeholderDoc) {
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
index faa6cffa8..ffdc6626d 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
@@ -47,6 +47,8 @@ export enum LayoutType {
 export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     static Instance: DocCreatorMenu;
 
+    private DEBUG_MODE: boolean = false;
+
     private _disposers: { [name: string]: IDisposer } = {};
 
     private _ref: HTMLDivElement | null = null;
@@ -122,8 +124,11 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     };
 
     @computed get docsToRender() {
-        return [1, 2, 3, 4];
-        //this._selectedTemplate ? NumListCast(this._dataViz?.layoutDoc.dataViz_selectedRows) : []; !!! put this back for GPT rendering
+        if (this.DEBUG_MODE){
+            return [1, 2, 3, 4];
+        } else {
+            return this._selectedTemplate ? NumListCast(this._dataViz?.layoutDoc.dataViz_selectedRows) : []; 
+        }
     }
 
     @computed get rowsCount() {
@@ -620,8 +625,6 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
         const renderedTemplates: (Template | undefined)[] = await Promise.all(renderedTemplatePromises);
 
-        templates.forEach(template => template.mainField.initRenderedDoc())
-
         setTimeout(() => {
             this.setSuggestedTemplates(templates);
             this._GPTLoading = false;
@@ -712,15 +715,6 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         const fields: string[] = Array.from(Object.keys(dv.records[0]));  
         const selectedRows = NumListCast(dv.layoutDoc.dataViz_selectedRows);
     
-        const rowContents: { [title: string]: string }[] = selectedRows.map(row => {
-            let values: { [title: string]: string } = {};
-            fields.forEach(col => {
-                values[col] = dv.records[row][col];
-            });
-    
-            return values;
-        });
-    
         const processContent = async (content: {[title: string]: string}) => {
 
             const templateCopy = template.cloneBase(); 
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
index 7ffb1884e..5ee047841 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
@@ -1,3 +1,4 @@
+import { reaction } from "mobx";
 import { Doc, DocListCast } from "../../../../../../fields/Doc";
 import { Docs } from "../../../../../documents/Documents";
 import { Col } from "../DocCreatorMenu";
@@ -11,7 +12,7 @@ export class DynamicField extends Field {
 
     protected renderedDocument: Doc;
 
-    constructor(settings: FieldSettings, id: number, parent?: Field) {
+    constructor(settings: FieldSettings, id: number, parent?: Field, protoDoc?: Doc) {
         super(settings, id, FieldUtils.initField, parent);
         if (!parent) {
             this.parent = this;
@@ -25,7 +26,7 @@ export class DynamicField extends Field {
         this.renderedDocument = this.initRenderedDoc(); //!!!
 
         // this.disposers.fieldList = reaction(
-        //     () => DocListCast(this.doc[Doc.LayoutFieldKey(this.doc)]),
+        //     () => DocListCast(this.renderedDoc[Doc.LayoutFieldKey(this.doc)]),
         //     docs => {
         //         this.handleFieldUpdate(docs);
         //     }
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
index 6c78e15ad..49931486c 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
@@ -1,14 +1,16 @@
 import { makeAutoObservable, makeObservable, reaction } from "mobx";
-import { Doc, DocListCast } from "../../../../../../fields/Doc";
+import { Doc, DocListCast, FieldType } from "../../../../../../fields/Doc";
 import { Col } from "../DocCreatorMenu";
 import { TemplateFieldSize, TemplateFieldType } from "../TemplateBackend";
 import { IDisposer } from "mobx-utils";
 import { DocumentType } from "../../../../../documents/DocumentTypes";
+import { SearchUtil } from "../../../../../util/SearchUtil";
+import { OmitKeys } from "../../../../../../ClientUtils";
 
 export abstract class Field {
 
     protected disposers: { [name: string]: IDisposer } = {};
-    private initField: (settings: FieldSettings, index: number, parent: Field) => Field;
+    private initField: (settings: FieldSettings, index: number, parent: Field, protoDoc?: Doc) => Field;
 
     protected abstract subfields: Field[];
 
@@ -21,7 +23,7 @@ export abstract class Field {
 
     protected abstract dimensions: FieldDimensions;
 
-    constructor(settings: FieldSettings, id: number, fieldFactory: (settings: FieldSettings, index: number, parent: Field) => Field, parent?: Field) {
+    constructor(settings: FieldSettings, id: number, fieldFactory: (settings: FieldSettings, index: number, parent: Field, protoDoc?: Doc) => Field, parent?: Field) {
         this.initField = fieldFactory;
         this.parent = parent ? parent : this;
         this.id = id;
@@ -47,6 +49,7 @@ export abstract class Field {
     };
 
     get renderedDoc(){ return this.renderedDocument };
+    get renderedDocChildDocs() { return DocListCast(this.renderedDocument[Doc.LayoutFieldKey(this.renderedDocument)])}
     get getDimensions() { return this.dimensions };
     get getID() { return this.id };
     get getDescription(): string { return this.settings.description ?? '' };
@@ -64,13 +67,14 @@ export abstract class Field {
 
     changeFieldType = (newType: ViewType): Field => {
         this.settings.viewType = newType;
-        const newField: Field = this.initField(this.settings, this.id, this.parent);
+        const newField: Field = this.initField(this.settings, this.id, this.parent, this.renderedDoc);
         this.parent.exchangeFields(newField, this);
         return newField;
     }
 
     exchangeFields = (newField: Field, oldField: Field) => {
         this.subfields.splice(this.subfields.indexOf(oldField), 1, newField);
+        // this.renderedDoc.
     }
 
     setupFieldChangeReaction = () => {
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
index d7cf24794..b60d66d1a 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
@@ -21,7 +21,7 @@ export class FieldUtils {
         return { width, height, coord };
     };
 
-    public static initField = (settings: FieldSettings, index: number, parent: Field): Field => { 
+    public static initField = (settings: FieldSettings, index: number, parent: Field, protoDoc?: Doc): Field => { 
         const id = Number(`${parent.getID}${index}`);
         switch (settings.viewType) {
             case ViewType.FREEFORM: case ViewType.CAROUSEL3D:
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticContentField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticContentField.tsx
index 627d3a939..8c50dc21d 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticContentField.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticContentField.tsx
@@ -14,7 +14,7 @@ export abstract class StaticContentField extends Field {
 
     protected dimensions: FieldDimensions;
 
-    constructor(settings: FieldSettings, parent: Field, id: number) {
+    constructor(settings: FieldSettings, parent: Field, id: number, protoDoc?: Doc) {
         super(settings, id, FieldUtils.initField, parent);
         this.dimensions = FieldUtils.getLocalDimensions({tl: settings.tl, br: settings.br}, this.parent.getDimensions);
         this.subfields = this.setupSubfields(this);
@@ -31,9 +31,9 @@ export class ImageTemplateField extends StaticContentField {
 
     protected renderedDocument: Doc;
 
-    constructor(settings: FieldSettings, parent: Field, id: number){
+    constructor(settings: FieldSettings, parent: Field, id: number, protoDoc?: Doc){
         super(settings, parent, id)
-        this.renderedDocument = this.initRenderedDoc();
+        this.renderedDocument = this.initRenderedDoc(protoDoc);
     }
 
     setContent = (url: string, type: ViewType) => { 
@@ -47,13 +47,21 @@ export class ImageTemplateField extends StaticContentField {
         }
     };
 
-    initRenderedDoc = (): Doc => {
+    initRenderedDoc = (proto?: Doc): Doc => {
         const url = String(this.content);
         let doc: Doc = Docs.Create.ImageDocument(url, {
             title: this.title,
             _layout_fitWidth: false,
-        });
-        FieldUtils.applyBasicOpts(doc, this.dimensions, this.settings);
+        }, /*proto*/);
+        // if (!proto) {
+            FieldUtils.applyBasicOpts(doc, this.dimensions, this.settings);
+        // } else {
+        //     doc.nativeWidth = this.dimensions.width;
+        //     doc.nativeHeight = this.dimensions.height;
+        //     doc._layout_nativeDimEditable = true;
+        // }
+
+        console.log('data is: ', doc['data']);
 
         this.renderedDocument = doc;
 
@@ -65,7 +73,7 @@ export class TextTemplateField extends StaticContentField {
 
     protected renderedDocument: Doc;
 
-    constructor(settings: FieldSettings, parent: Field, id: number){
+    constructor(settings: FieldSettings, parent: Field, id: number, protoDoc?: Doc){
         super(settings, parent, id)
         this.renderedDocument = this.initRenderedDoc();
     }
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
index a80df8468..e8e9dca4f 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
@@ -90,7 +90,6 @@ export class Template {
     isValidTemplate = (cols: Col[]) => {
         const matches: number[][] = this.getMatches(cols);
         const maxMatches: number = this.maxMatches(matches);
-        console.log('title: ', this.mainField.getTitle(), ' matches: ', matches, ' max: ', maxMatches, ' num content fields: ', this.contentFields.length)
         return maxMatches === this.contentFields.length;
     }
 
-- 
cgit v1.2.3-70-g09d2


From f7e28d954902bf9e7e8567ce06b6eb03b6cd92ef Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Sun, 2 Mar 2025 03:19:21 -0500
Subject: Slight refactors (with so much wasted time trying for larger ones)

---
 src/client/documents/Documents.ts                  |   1 +
 .../DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx   |  32 ++++--
 .../DocCreatorMenu/FieldTypes/DecorationField.tsx  |  19 ++--
 .../DocCreatorMenu/FieldTypes/DynamicField.tsx     |  99 +++++++++++-------
 .../DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx | 114 ++++++++-------------
 .../DocCreatorMenu/FieldTypes/FieldUtils.tsx       |  53 +---------
 .../FieldTypes/StaticContentField.tsx              |  59 +++++------
 .../nodes/DataVizBox/DocCreatorMenu/Template.tsx   |   4 +-
 .../DataVizBox/DocCreatorMenu/TemplateBackend.tsx  |   8 +-
 9 files changed, 173 insertions(+), 216 deletions(-)

(limited to 'src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx')

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 0a7047128..b35845de9 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -285,6 +285,7 @@ export class DocumentOptions {
     _layout_showSidebar?: BOOLt = new BoolInfo('whether an annotationsidebar should be displayed for text docuemnts');
     _layout_showCaption?: string; // which field to display in the caption area.  leave empty to have no caption
     _layout_showTags?: BOOLt = new BoolInfo('whether to show the list of document tags at the bottom of a DocView');
+    _layout_hideScroll?: BOOLt = new BoolInfo('whether to hide scroll bars on the document');
 
     _chromeHidden?: BOOLt = new BoolInfo('whether the editing chrome for a document is hidden');
     hideClickBehaviors?: BOOLt = new BoolInfo('whether to hide click behaviors in context menu');
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
index faa6cffa8..cc161e688 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
@@ -47,6 +47,8 @@ export enum LayoutType {
 export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     static Instance: DocCreatorMenu;
 
+    private DEBUG_MODE: boolean = false;
+
     private _disposers: { [name: string]: IDisposer } = {};
 
     private _ref: HTMLDivElement | null = null;
@@ -122,8 +124,11 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     };
 
     @computed get docsToRender() {
-        return [1, 2, 3, 4];
-        //this._selectedTemplate ? NumListCast(this._dataViz?.layoutDoc.dataViz_selectedRows) : []; !!! put this back for GPT rendering
+        if (this.DEBUG_MODE) {
+            return [1, 2, 3, 4];
+        } else {
+            return this._selectedTemplate ? NumListCast(this._dataViz?.layoutDoc.dataViz_selectedRows) : [];
+        }
     }
 
     @computed get rowsCount() {
@@ -607,20 +612,27 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     };
 
     generatePresetTemplates = async () => {
-        this._dataViz?.updateColDefaults();
 
-        const cols = this.fieldsInfos;
-        const templates = this.templateManager.getValidTemplates(cols);
+        const templates: Template[] = [];
 
-        console.log(templates)
+        if (this.DEBUG_MODE) {
+            templates.push(...this.templateManager.templates)
+        } else {
+            this._dataViz?.updateColDefaults();
 
-        const assignments: [Template, { [field: number]: Col }][] = await this.assignColsToFields(templates, cols);
+            const cols = this.fieldsInfos;
+            templates.push(...this.templateManager.getValidTemplates(cols));
 
-        const renderedTemplatePromises: Promise<Template | undefined>[] = assignments.map(([template, assignments]) => this.applyGPTContentToTemplate(template, assignments));
+            console.log(templates)
 
-        const renderedTemplates: (Template | undefined)[] = await Promise.all(renderedTemplatePromises);
+            const assignments: [Template, { [field: number]: Col }][] = await this.assignColsToFields(templates, cols);
+
+            const renderedTemplatePromises: Promise<Template | undefined>[] = assignments.map(([template, assignments]) => this.applyGPTContentToTemplate(template, assignments));
+
+            const renderedTemplates: (Template | undefined)[] = await Promise.all(renderedTemplatePromises);
+        }
 
-        templates.forEach(template => template.mainField.initRenderedDoc())
+        // templates.forEach(template => template.mainField.initRenderedDoc())
 
         setTimeout(() => {
             this.setSuggestedTemplates(templates);
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DecorationField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DecorationField.tsx
index efe398aaa..62f5504a8 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DecorationField.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DecorationField.tsx
@@ -1,37 +1,34 @@
 import { Doc, DocListCast } from "../../../../../../fields/Doc";
 import { Docs, DocumentOptions } from "../../../../../documents/Documents";
-import { FieldUtils } from "./FieldUtils";
 import { Field, FieldDimensions, FieldSettings, ViewType } from "./Field";
 import { RichTextField } from "../../../../../../fields/RichTextField";
 import { DocData } from "../../../../../../fields/DocSymbols";
 import { ImageField } from "../../../../../../fields/URLField";
+import { FieldUtils } from "./FieldUtils";
 
 export class DecorationField extends Field {
 
     protected content: string = ''; 
     protected subfields: Field[];
 
-    protected renderedDocument: Doc;
-
-    protected dimensions: FieldDimensions;
+    protected Document: Doc;
 
-    constructor(settings: FieldSettings, parent: Field, id: number) {
+    constructor(settings: FieldSettings, id: number, parent: Field) {
         super(settings, id, FieldUtils.initField, parent);
-        this.dimensions = FieldUtils.getLocalDimensions({tl: settings.tl, br: settings.br}, this.parent.getDimensions);
         this.subfields = this.setupSubfields(this);
-        this.renderedDocument = this.initRenderedDoc();
+        this.Document = this.initializeDocument();
     };
 
     setContent = (content: string, type?: ViewType) => { return }
     getContent = () => { return 'none'};
     get isContentField(): boolean { return false };
 
-    initRenderedDoc = (): Doc => {
+    initializeDocument = (): Doc => {
         const renderedSubfields: Doc[] = this.subfields.map(field => field.renderedDoc);
-        let doc: Doc = Docs.Create.FreeformDocument(renderedSubfields, { title: this.title, });
-        FieldUtils.applyBasicOpts(doc, this.dimensions, this.settings);
+        this.settings.opts.title = this.title;
+        let doc: Doc = Docs.Create.FreeformDocument(renderedSubfields, this.settings.opts);
 
-        this.renderedDocument = doc;
+        this.Document = doc;
 
         return doc;
     };
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
index 7ffb1884e..59a955c66 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
@@ -1,58 +1,36 @@
+import { makeAutoObservable, makeObservable, reaction } from "mobx";
 import { Doc, DocListCast } from "../../../../../../fields/Doc";
 import { Docs } from "../../../../../documents/Documents";
 import { Col } from "../DocCreatorMenu";
+import { TemplateLayouts } from "../TemplateBackend";
 import { Field, FieldDimensions, FieldSettings, ViewType } from "./Field";
+import { IDisposer } from "mobx-utils";
 import { FieldUtils } from "./FieldUtils";
 
 export class DynamicField extends Field {
-    protected parent: Field;
-    protected dimensions: FieldDimensions;
     protected subfields: Field[];
 
-    protected renderedDocument: Doc;
+    protected Document!: Doc;
 
     constructor(settings: FieldSettings, id: number, parent?: Field) {
         super(settings, id, FieldUtils.initField, parent);
-        if (!parent) {
-            this.parent = this;
-            this.dimensions = {width: this.settings.br[0] - this.settings.tl[0], height: this.settings.br[1] - this.settings.tl[1], coord: {x: this.settings.tl[0], y: this.settings.tl[1]}};
-        } else {
-            this.parent = parent;
-            this.dimensions = FieldUtils.getLocalDimensions({tl: settings.tl, br: settings.br}, this.parent.getDimensions);
-        }
-        //console.log('new field dimensions: ', this.dimensions);
         this.subfields = this.setupSubfields(this);
-        this.renderedDocument = this.initRenderedDoc(); //!!!
-
-        // this.disposers.fieldList = reaction(
-        //     () => DocListCast(this.doc[Doc.LayoutFieldKey(this.doc)]),
-        //     docs => {
-        //         this.handleFieldUpdate(docs);
-        //     }
-        // );
+        this.initializeDocument();
     }
 
     setContent = (content: string, type: ViewType) => { return };
     getContent = () => { return '' };
     get isContentField(): boolean { return false };
 
+    addChildToDocument = (doc: Doc) => {
+        Doc.SetContainer(doc, this.Document);
+    }
+
     matches = (cols: Col[]): Array<number> => {
         return [];
     }
 
-    getChildDimensions = (coords: { tl: [number, number]; br: [number, number] }): FieldDimensions => {
-        const l = (coords.tl[0] * this.dimensions.height) / 2;
-        const t = coords.tl[1] * this.dimensions.width / 2; //prettier-ignore
-        const r = (coords.br[0] * this.dimensions.height) / 2;
-        const b = coords.br[1] * this.dimensions.width / 2; //prettier-ignore
-        const width = r - l;
-        const height = b - t;
-        const coord = { x: l, y: t };
-        return { width, height, coord };
-    };
-
-    initRenderedDoc = (): Doc => {
-        console.log('dynamic field updated');
+    initializeDocument = (): Doc => {
         let doc: Doc;
         const renderedSubfields: Doc[] = this.subfields.map(field => field.renderedDoc);
         switch (this.settings.viewType) {
@@ -60,24 +38,71 @@ export class DynamicField extends Field {
                 doc = Docs.Create.Carousel3DDocument(renderedSubfields, {
                     title: this.title,
                 });
-                FieldUtils.applyBasicOpts(doc, this.dimensions, this.settings);
                 break;
             case ViewType.FREEFORM:
                 doc = Docs.Create.FreeformDocument(renderedSubfields, {
                     title: this.title,
                 });
-                FieldUtils.applyBasicOpts(doc, this.dimensions, this.settings);
                 break;
             default:
-                doc = Docs.Create.Carousel3DDocument(renderedSubfields, {
+                doc = Docs.Create.FreeformDocument(renderedSubfields, {
                     title: this.title,
                 });
-                FieldUtils.applyBasicOpts(doc, this.dimensions, this.settings);
             break;
         }
 
-        this.renderedDocument = doc;
+        this.Document = doc;
         return doc;
     }
 
 }
+
+// export class DynamicField extends Field {
+//     protected subfields: Field[];
+
+//     protected Document!: Doc;
+
+//     constructor(settings: FieldSettings, id: number, parent?: Field) {
+//         super(settings, id, parent);
+//         this.subfields = this.setupSubfields(this);
+//         this.initializeDocument();
+//     }
+
+//     setContent = (content: string, type: ViewType) => { return };
+//     getContent = () => { return '' };
+//     get isContentField(): boolean { return false };
+
+//     addChildToDocument = (doc: Doc) => {
+//         Doc.SetContainer(doc, this.Document);
+//     }
+
+//     matches = (cols: Col[]): Array<number> => {
+//         return [];
+//     }
+
+//     initializeDocument = (): Doc => {
+//         let doc: Doc;
+//         const renderedSubfields: Doc[] = this.subfields.map(field => field.renderedDoc);
+//         switch (this.settings.viewType) {
+//             case ViewType.CAROUSEL3D:
+//                 doc = Docs.Create.Carousel3DDocument(renderedSubfields, {
+//                     title: this.title,
+//                 });
+//                 break;
+//             case ViewType.FREEFORM:
+//                 doc = Docs.Create.FreeformDocument(renderedSubfields, {
+//                     title: this.title,
+//                 });
+//                 break;
+//             default:
+//                 doc = Docs.Create.FreeformDocument(renderedSubfields, {
+//                     title: this.title,
+//                 });
+//             break;
+//         }
+
+//         this.Document = doc;
+//         return doc;
+//     }
+
+// }
\ No newline at end of file
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
index 6c78e15ad..df98e6181 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
@@ -4,22 +4,24 @@ import { Col } from "../DocCreatorMenu";
 import { TemplateFieldSize, TemplateFieldType } from "../TemplateBackend";
 import { IDisposer } from "mobx-utils";
 import { DocumentType } from "../../../../../documents/DocumentTypes";
+import { Partial } from "@react-spring/web";
+import { DocumentOptions } from "../../../../../documents/Documents";
 
 export abstract class Field {
 
     protected disposers: { [name: string]: IDisposer } = {};
+    
     private initField: (settings: FieldSettings, index: number, parent: Field) => Field;
 
     protected abstract subfields: Field[];
 
-    protected abstract renderedDocument: Doc;
+    protected abstract Document: Doc;
 
     protected parent: Field;
     protected id: number;
     protected settings: FieldSettings;
     protected title: string = '';
-
-    protected abstract dimensions: FieldDimensions;
+    protected dimensions: FieldDimensions;
 
     constructor(settings: FieldSettings, id: number, fieldFactory: (settings: FieldSettings, index: number, parent: Field) => Field, parent?: Field) {
         this.initField = fieldFactory;
@@ -27,10 +29,13 @@ export abstract class Field {
         this.id = id;
         this.settings = settings;
         this.title = settings.title ?? '';
+        this.dimensions = this.getLocalDimensions({tl: this.settings.tl, br: this.settings.br}, this.parent.getDimensions);
+        this.applyBasicOpts(this.dimensions, settings);
 
         this.disposers.fieldList = reaction(
-            () => DocListCast(this.renderedDocument[Doc.LayoutFieldKey(this.renderedDocument)]),
+            () => DocListCast(this.Document[Doc.LayoutFieldKey(this.Document)]),
             docs => {
+                console.log('updated')
                 this.handleFieldUpdate(docs);
             }
         );
@@ -46,7 +51,7 @@ export abstract class Field {
         return fields;
     };
 
-    get renderedDoc(){ return this.renderedDocument };
+    get renderedDoc(){ return this.Document };
     get getDimensions() { return this.dimensions };
     get getID() { return this.id };
     get getDescription(): string { return this.settings.description ?? '' };
@@ -54,7 +59,7 @@ export abstract class Field {
 
     setTitle = (title: string) => { 
         this.title = title;
-        this.renderedDocument.title = title;
+        this.Document.title = title;
     };
     getTitle = () => { return this.title };
 
@@ -73,66 +78,22 @@ export abstract class Field {
         this.subfields.splice(this.subfields.indexOf(oldField), 1, newField);
     }
 
-    setupFieldChangeReaction = () => {
-
-    }
-
     addFieldFromDoc = (doc: Doc) => {
         console.log('add field called');
-        const par = this.renderedDocument;
+        const par = this.Document;
         const settings: FieldSettings = {
             tl: [Number(doc._x) / Number(par._width), Number(doc._y) / Number(par._height)],
             br: [(Number(doc._x) + Number(doc._width)) / Number(par._width), (Number(doc._y) + Number(doc._height)) / Number(par._height)],
             viewType: doc.type === DocumentType.COL ? ViewType.FREEFORM : ViewType.STATIC,
             opts: {},
         };
-
-        Object.getOwnPropertyNames(FieldOpts.prototype).forEach(([key, value]) => {
-            switch (key) {
-                case 'text_fontColor':
-                case 'backgroundColor':
-                case 'borderWidth':
-                case 'borderColor':
-                    settings.opts[key] = String(doc[key]);
-                    break;
-            
-                case '_layout_borderRounding':
-                case 'opacity':
-                case '_rotation':
-                    settings.opts[key] = Number(doc[key]);
-                    break;
-            
-                case 'contentBold':
-                    settings.opts[key] = Boolean(doc[key]);
-                    break;
-            
-                case 'hCentering':
-                    settings.opts[key] = String(doc[key]) as 'h-left' | 'h-center' | 'h-right';
-                    break;
-                case 'contentYCentering':
-                    settings.opts[key] = String(doc[key]) as 'top' | 'center' | 'bottom';
-                    break;
-                case 'textTransform':
-                    settings.opts[key] = String(doc[key]) as 'uppercase' | 'lowercase';
-                    break;
-                case 'fieldViewType':
-                    settings.opts[key] = String(doc[key]) as 'freeform' | 'stacked';
-                    break;
-            
-                default:
-                    break;
-            }
-        });
         
         const newField: Field = this.initField(settings, this.subfields.length, this);
         this.subfields.push(newField);
     };
 
-    addField = (type?: ViewType) => {
-        
-    }
-
     removeField = (field: Field) => {
+        console.log('removefield called')
         this.subfields.splice(this.subfields.indexOf(field), 1);
         field.dispose();
     };
@@ -145,11 +106,11 @@ export abstract class Field {
 
     applyAttributes(field: Field) {
         field.setTitle(this.title);
-        field.initRenderedDoc(this.renderedDoc);
+        field.initializeDocument(this.renderedDoc);
         field.subfields = this.subfields;
     }
 
-    abstract initRenderedDoc(oldDoc?: Doc): void;
+    abstract initializeDocument(oldDoc?: Doc): void;
 
     dispose = () => {
         Object.values(this.disposers).forEach(disposer => disposer?.());
@@ -191,12 +152,39 @@ export abstract class Field {
         return matches;
     };
 
+    private getLocalDimensions = (coords: { tl: [number, number]; br: [number, number] }, parentDimensions: FieldDimensions): FieldDimensions => {
+        if (!parentDimensions) {
+            return {width: coords.br[0] - coords.tl[0], height: coords.br[1] - coords.tl[1], coord: {x: coords.tl[0], y: coords.tl[1]}};
+        }
+        const l = (coords.tl[0] * parentDimensions.width) / 2;
+        const t = coords.tl[1] * parentDimensions.height / 2; //prettier-ignore
+        const r = (coords.br[0] * parentDimensions.width) / 2;
+        const b = coords.br[1] * parentDimensions.height / 2; //prettier-ignore
+        const width = r - l;
+        const height = b - t;
+        const coord = { x: l, y: t };
+        return { width, height, coord };
+    };
+
+    private applyBasicOpts = (dimensions: FieldDimensions, settings: FieldSettings) => {
+        const opts: DocumentOptions = settings.opts;
+        opts.isDefaultTemplateDoc = true;
+        opts._layout_hideScroll = true;
+        opts.x = dimensions.coord.x;
+        opts.y = dimensions.coord.y;
+        opts._height = dimensions.height;
+        opts._width = dimensions.width;
+        opts._nativeWidth = dimensions.width;
+        opts._nativeHeight = dimensions.height;
+        opts._layout_nativeDimEditable = true;
+    };
+
 }
 
 export type FieldSettings = {
     tl: [number, number];
     br: [number, number];
-    opts: FieldOpts;
+    opts: DocumentOptions;
     viewType: ViewType;
     title?: string;
     subfields?: FieldSettings[];
@@ -219,19 +207,3 @@ export type FieldDimensions = {
     height: number;
     coord: {x: number, y: number};
 }
-
-export class FieldOpts {
-    backgroundColor?: string;
-    text_fontColor?: string;
-    _layout_borderRounding?: number;
-    borderWidth?: string;
-    borderColor?: string;
-    hCentering?: 'h-left' | 'h-center' | 'h-right';
-    contentYCentering?: 'top' | 'center' | 'bottom';
-    opacity?: number;
-    _rotation?: number;
-    //animation?: boolean;
-    contentBold?: boolean;
-    textTransform?: 'uppercase' | 'lowercase';
-    fieldViewType?: 'freeform' | 'stacked';
-}
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
index d7cf24794..f3e4130a4 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
@@ -1,25 +1,9 @@
-import { Doc } from "../../../../../../fields/Doc";
-import { ComputedField, ScriptField } from "../../../../../../fields/ScriptField";
-import { Col } from "../DocCreatorMenu";
-import { TemplateFieldSize, TemplateFieldType, TemplateLayouts } from "../TemplateBackend";
 import { DynamicField } from "./DynamicField";
-import { Field, FieldDimensions, FieldSettings, ViewType } from "./Field";
+import { Field, FieldSettings, ViewType } from "./Field";
 import { TextTemplateField, ImageTemplateField } from "./StaticContentField";
 import { DecorationField } from "./DecorationField";
 
 export class FieldUtils {
-    public static getLocalDimensions = (coords: { tl: [number, number]; br: [number, number] }, parentDimensions: FieldDimensions): FieldDimensions => {
-        //console.log('parent dimensions', parentDimensions, 'coords: ', coords);
-        const l = (coords.tl[0] * parentDimensions.width) / 2;
-        const t = coords.tl[1] * parentDimensions.height / 2; //prettier-ignore
-        const r = (coords.br[0] * parentDimensions.width) / 2;
-        const b = coords.br[1] * parentDimensions.height / 2; //prettier-ignore
-        const width = r - l;
-        const height = b - t;
-        const coord = { x: l, y: t };
-        //console.log('width: ', width, 'height: ', height);
-        return { width, height, coord };
-    };
 
     public static initField = (settings: FieldSettings, index: number, parent: Field): Field => { 
         const id = Number(`${parent.getID}${index}`);
@@ -27,42 +11,15 @@ export class FieldUtils {
             case ViewType.FREEFORM: case ViewType.CAROUSEL3D:
                 return new DynamicField(settings, id, parent);
             case ViewType.IMG:
-                return new ImageTemplateField(settings, parent, id);
+                return new ImageTemplateField(settings, id, parent);
             case ViewType.TEXT:
-                return new TextTemplateField(settings, parent, id);
+                return new TextTemplateField(settings, id, parent);
             case ViewType.DEC:
-                return new DecorationField(settings, parent, id);
+                return new DecorationField(settings, id, parent);
         }
-        return new TextTemplateField(settings, parent, id);
+        return new TextTemplateField(settings, id, parent);
     }
 
-    public static textProperties: string[] = [
-        "textTransform",
-        "contentBold",
-        "text_fontColor",
-        "hCentering",
-    ]
-
-    public static applyBasicOpts = (doc: Doc, parentDimensions: FieldDimensions, settings: FieldSettings, oldDoc?: Doc) => {
-        const opts = settings.opts;
-        doc.isDefaultTemplateDoc = oldDoc ? oldDoc.isDefaultTemplateDoc : true;
-        doc._layout_hideScroll = oldDoc ? oldDoc._layout_hideScroll : true;
-        doc.x = oldDoc ? oldDoc.x : parentDimensions.coord.x;
-        doc.y = oldDoc ? oldDoc.y : parentDimensions.coord.y;
-        doc._height = oldDoc ? oldDoc.height : parentDimensions.height;
-        doc._width = oldDoc ? oldDoc.width : parentDimensions.width;
-        doc.backgroundColor = oldDoc ? oldDoc.backgroundColor : opts.backgroundColor ?? '';
-        //doc._layout_borderRounding = !opts._layout_borderRounding ? '0px' : ScriptField.MakeFunction(`${opts._layout_borderRounding} * this.width + 'px'`);
-        doc.borderColor = oldDoc ? oldDoc.borderColor : opts.borderColor;
-        doc.borderWidth = oldDoc ? oldDoc.borderWidth : opts.borderWidth;
-        doc.opacity = oldDoc ? oldDoc.opacity : opts.opacity;
-        doc._rotation = oldDoc ? oldDoc._rotation : opts._rotation;
-        doc.hCentering = oldDoc ? oldDoc.hCentering : opts.hCentering;
-        doc.nativeWidth = parentDimensions.width;
-        doc.nativeHeight = parentDimensions.height;
-        doc._layout_nativeDimEditable = true;
-    };
-
     public static calculateFontSize = (contWidth: number, contHeight: number, text: string, uppercase: boolean): number => {
         const words: string[] = text.split(/\s+/).filter(Boolean);
 
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticContentField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticContentField.tsx
index 627d3a939..63fe530a6 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticContentField.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticContentField.tsx
@@ -1,22 +1,20 @@
 import { Doc, DocListCast } from "../../../../../../fields/Doc";
 import { Docs, DocumentOptions } from "../../../../../documents/Documents";
-import { FieldUtils } from "./FieldUtils";
 import { Field, FieldDimensions, FieldSettings, ViewType } from "./Field";
 import { RichTextField } from "../../../../../../fields/RichTextField";
 import { DocData } from "../../../../../../fields/DocSymbols";
 import { ImageField } from "../../../../../../fields/URLField";
 import { ViewComponentType } from "@fullcalendar/core";
+import { DynamicField } from "./DynamicField";
+import { FieldUtils } from "./FieldUtils";
 
 export abstract class StaticContentField extends Field {
 
     protected content: string = ''; 
     protected subfields: Field[];
 
-    protected dimensions: FieldDimensions;
-
     constructor(settings: FieldSettings, parent: Field, id: number) {
         super(settings, id, FieldUtils.initField, parent);
-        this.dimensions = FieldUtils.getLocalDimensions({tl: settings.tl, br: settings.br}, this.parent.getDimensions);
         this.subfields = this.setupSubfields(this);
     };
 
@@ -24,22 +22,22 @@ export abstract class StaticContentField extends Field {
     getContent = () => { return this.content ?? 'unset'};
     get isContentField(): boolean { return true };
 
-    abstract initRenderedDoc(): Doc;
+    abstract initializeDocument(): Doc;
 }
 
 export class ImageTemplateField extends StaticContentField {
 
-    protected renderedDocument: Doc;
+    protected Document: Doc;
 
-    constructor(settings: FieldSettings, parent: Field, id: number){
+    constructor(settings: FieldSettings, id: number, parent: Field){
         super(settings, parent, id)
-        this.renderedDocument = this.initRenderedDoc();
+        this.Document = this.initializeDocument();
     }
 
     setContent = (url: string, type: ViewType) => { 
         if (type === ViewType.IMG){
             const imgField = new ImageField(url);
-            this.renderedDocument[DocData]['data'] = imgField;
+            this.Document[DocData]['data'] = imgField;
             this.content = url;
         } else {
             const updatedField = this.changeFieldType(type);
@@ -47,15 +45,14 @@ export class ImageTemplateField extends StaticContentField {
         }
     };
 
-    initRenderedDoc = (): Doc => {
+    initializeDocument = (): Doc => {
         const url = String(this.content);
-        let doc: Doc = Docs.Create.ImageDocument(url, {
-            title: this.title,
-            _layout_fitWidth: false,
-        });
-        FieldUtils.applyBasicOpts(doc, this.dimensions, this.settings);
+        this.settings.opts.title = this.title;
+        this.settings.opts._layout_fitWidth = false;
+
+        let doc: Doc = Docs.Create.ImageDocument(url, this.settings.opts);
 
-        this.renderedDocument = doc;
+        this.Document = doc;
 
         return doc;
     };
@@ -63,11 +60,11 @@ export class ImageTemplateField extends StaticContentField {
 
 export class TextTemplateField extends StaticContentField {
 
-    protected renderedDocument: Doc;
+    protected Document: Doc;
 
-    constructor(settings: FieldSettings, parent: Field, id: number){
+    constructor(settings: FieldSettings, id: number, parent: Field){
         super(settings, parent, id)
-        this.renderedDocument = this.initRenderedDoc();
+        this.Document = this.initializeDocument();
     }
 
     setContent = (text: string, type: ViewType) => { 
@@ -92,27 +89,23 @@ export class TextTemplateField extends StaticContentField {
             };
             this.content = text;
             const field = new RichTextField(JSON.stringify(rtf), text);
-            this.renderedDocument[DocData]['text'] = field;
+            this.Document[DocData]['text'] = field;
         } else {
             const updatedField = this.changeFieldType(type);
             updatedField.setContent(text, type);
         }
     };
 
-    initRenderedDoc = (): Doc => {
+    initializeDocument = (): Doc => {
         const opts = this.settings.opts;
-        const text = String(this.content);
-        let doc: Doc = Docs.Create.TextDocument(text, {
-            title: this.title,
-            text_fontColor: opts.text_fontColor,
-            contentBold: opts.contentBold,
-            textTransform: opts.textTransform,
-            color: opts.text_fontColor,
-            _text_fontSize: `${FieldUtils.calculateFontSize(this.dimensions.width, this.dimensions.height, text, true)}`
-        });
-        FieldUtils.applyBasicOpts(doc, this.dimensions, this.settings);
-
-        this.renderedDocument = doc;
+        const text = this.content;
+
+        // opts._text_fontSize = `${FieldUtils.calculateFontSize(this.dimensions.width, this.dimensions.height, text, true)}`;
+        opts.title = this.title;
+
+        let doc: Doc = Docs.Create.TextDocument(text, opts);
+
+        this.Document = doc;
 
         return doc;
     };
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
index a80df8468..687b655d1 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
@@ -38,7 +38,7 @@ export class Template {
             const matchingField: Field = this.allFields.filter(f => f.getID === field.getID)[0];
             matchingField.applyAttributes(field);
         })
-        clone.mainField.initRenderedDoc();
+        clone.mainField.initializeDocument();
         return clone;
     }
 
@@ -83,7 +83,7 @@ export class Template {
 
     resetToBase = () => {
         this.allFields.forEach(field => {
-            field.initRenderedDoc();
+            field.initializeDocument();
         })
     }
 
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
index 583b2f472..b1e06206f 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
@@ -1,4 +1,4 @@
-import { FieldOpts, FieldSettings, ViewType } from "./FieldTypes/Field";
+import { FieldSettings, ViewType } from "./FieldTypes/Field";
 
 export enum TemplateFieldType {
     TEXT = 'text',
@@ -34,7 +34,7 @@ export class TemplateLayouts {
         viewType: ViewType.FREEFORM,
         opts: {
             backgroundColor: '#C0B887',
-            _layout_borderRounding: .05,
+            _layout_borderRounding: '.05',
             //borderColor: '#6B461F',
             //borderWidth: '12',
         },
@@ -61,7 +61,7 @@ export class TemplateLayouts {
                 sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
                 description: 'The main focus of the template; could be an image, long text, etc.',
                 opts: {
-                    _layout_borderRounding: .05,
+                    _layout_borderRounding: '.05',
                     borderColor: '#8F5B25',
                     borderWidth: '6',
                     backgroundColor: '#CECAB9',
@@ -88,7 +88,7 @@ export class TemplateLayouts {
                 sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
                 description: 'A medium-sized field for medium/long text.',
                 opts: {
-                    _layout_borderRounding: .05,
+                    _layout_borderRounding: '.05',
                     borderColor: '#8F5B25',
                     borderWidth: '6',
                     backgroundColor: '#CECAB9',
-- 
cgit v1.2.3-70-g09d2


From 2c7462f38a086f156a7d2e20dc15b822b7d7b1fb Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Wed, 5 Mar 2025 02:19:04 -0500
Subject: working on template cloning

---
 .../DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx   | 28 ++++---
 .../DocCreatorMenu/FieldTypes/DynamicField.tsx     | 13 +++-
 .../DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx | 90 ++++++++++++++--------
 .../DocCreatorMenu/FieldTypes/FieldUtils.tsx       |  4 +-
 .../FieldTypes/StaticContentField.tsx              | 42 ++++------
 .../nodes/DataVizBox/DocCreatorMenu/Template.tsx   | 27 ++++---
 6 files changed, 120 insertions(+), 84 deletions(-)

(limited to 'src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx')

diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
index cc161e688..099d082d3 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
@@ -632,7 +632,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
             const renderedTemplates: (Template | undefined)[] = await Promise.all(renderedTemplatePromises);
         }
 
-        // templates.forEach(template => template.mainField.initRenderedDoc())
+        templates.forEach(template => template.mainField.initializeDocument())
 
         setTimeout(() => {
             this.setSuggestedTemplates(templates);
@@ -695,7 +695,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
             const res = await gptAPICall(`${++this._callCount}: ${prompt}`, GPTCallType.FILL);
 
-            console.log('prompt: ', prompt, ' response: ', res);
+            // console.log('prompt: ', prompt, ' response: ', res);
 
             if (res) {
                 const assignments: { [title: string]: { number: string; content: string } } = JSON.parse(res);
@@ -740,6 +740,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
             fields.filter(title => title).forEach(title => {
                 const field = templateCopy.getFieldByTitle(title);
                 if (field === undefined) return;
+                console.log('setting content to: ', content[title]);
                 field.setContent(content[title], field.viewType);
             });
     
@@ -769,17 +770,19 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         };
 
         const rows = [1, 2, 3, 4];
-    
-        //const promises = rowContents.map(content => processContent(content));
-    
-        const promises = rows.map(row => processContent({}));
+        
+        let docs: Promise<Doc>[];
+        if (this.DEBUG_MODE) {
+            docs = rows.map(() => processContent({}));
+        } else {
+            docs = rowContents.map(content => processContent(content));
+        }
 
-        const renderedDocs = await Promise.all(promises);
+        const renderedDocs = await Promise.all(docs);
 
-        this._docsRendering = false; // removes loading indicator
+        //renderedDocs.forEach(doc => {console.log(doc._height, doc._width); doc._height = 400; doc._width = 400});
 
-        console.log('docs: ', renderedDocs);
-        console.log('first doc height: ', renderedDocs[0]._height);
+        this._docsRendering = false; // removes loading indicator
 
         return renderedDocs;
     }
@@ -1032,6 +1035,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
     applyLayout = (collection: Doc, docs: Doc[]) => {
         const { horizontalSpan, verticalSpan } = this.previewInfo;
+        console.log(this.previewInfo)
         collection._height = verticalSpan;
         collection._width = horizontalSpan;
 
@@ -1111,7 +1115,9 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
             title: 'title',
             backgroundColor: 'gray',
             x: 200,
-            y: 200
+            y: 200,
+            _width: 4000,
+            _height: 4000,
         });
 
         this.applyLayout(collection, this._fullyRenderedDocs);
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
index e17ad3860..c9e76dcbd 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
@@ -1,21 +1,25 @@
 import { makeAutoObservable, makeObservable, reaction } from "mobx";
 import { Doc, DocListCast } from "../../../../../../fields/Doc";
-import { Docs } from "../../../../../documents/Documents";
+import { Docs, DocumentOptions } from "../../../../../documents/Documents";
 import { Col } from "../DocCreatorMenu";
 import { TemplateLayouts } from "../TemplateBackend";
 import { Field, FieldDimensions, FieldSettings, ViewType } from "./Field";
 import { IDisposer } from "mobx-utils";
 import { FieldUtils } from "./FieldUtils";
+import { random } from "lodash";
 
 export class DynamicField extends Field {
     protected subfields: Field[];
 
     protected Document!: Doc;
 
+    private idd: number;
+
     constructor(settings: FieldSettings, id: number, parent?: Field) {
         super(settings, id, FieldUtils.initField, parent);
         this.subfields = this.setupSubfields(this);
         this.initializeDocument();
+        this.idd = random(0, 1000);
     }
 
     setContent = (content: string, type: ViewType) => { return };
@@ -30,7 +34,7 @@ export class DynamicField extends Field {
         return [];
     }
 
-    initializeDocument = (): Doc => {
+    initializeDocument = (oldOpts?: DocumentOptions): Doc => {
         let doc: Doc;
         const renderedSubfields: Doc[] = this.subfields.map(field => field.renderedDoc);
         this.settings.opts.title = this.title;
@@ -39,14 +43,15 @@ export class DynamicField extends Field {
                 doc = Docs.Create.Carousel3DDocument(renderedSubfields, this.settings.opts);
                 break;
             case ViewType.FREEFORM:
-                doc = Docs.Create.FreeformDocument(renderedSubfields, this.settings.opts);
+                doc = Docs.Create.FreeformDocument(renderedSubfields, oldOpts ?? this.settings.opts);
                 break;
             default:
                 doc = Docs.Create.FreeformDocument(renderedSubfields, this.settings.opts);
-            break;
+                break;
         }
 
         this.Document = doc;
+        console.log('width: ', doc._width, ' height: ', doc._height, ' id: ', this.idd)
         return doc;
     }
 
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
index 07278f4ee..afdbeeadd 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
@@ -1,4 +1,4 @@
-import { makeAutoObservable, makeObservable, reaction } from "mobx";
+import { computed, makeAutoObservable, makeObservable, reaction } from "mobx";
 import { Doc, DocListCast } from "../../../../../../fields/Doc";
 import { Col } from "../DocCreatorMenu";
 import { TemplateFieldSize, TemplateFieldType } from "../TemplateBackend";
@@ -8,12 +8,16 @@ import { Partial } from "@react-spring/web";
 import { DocumentOptions } from "../../../../../documents/Documents";
 import { List } from "../../../../../../fields/List";
 import { runInThisContext } from "vm";
+import { DocData } from "../../../../../../fields/DocSymbols";
+import { ObjectField } from "../../../../../../fields/ObjectField";
+import { ComputedField } from "../../../../../../fields/ScriptField";
+import { Copy } from "../../../../../../fields/FieldSymbols";
 
 export abstract class Field {
 
     protected disposers: { [name: string]: IDisposer } = {};
     
-    private initField: (settings: FieldSettings, index: number, parent: Field) => Field;
+    protected initField: (settings: FieldSettings, index: number, parent: Field, sameId?: boolean) => Field;
 
     protected abstract subfields: Field[];
 
@@ -34,13 +38,13 @@ export abstract class Field {
         this.dimensions = this.getLocalDimensions({tl: this.settings.tl, br: this.settings.br}, this.parent.getDimensions);
         this.applyBasicOpts(this.dimensions, settings);
 
-        this.disposers.fieldList = reaction(
-            () => DocListCast(this.Document[Doc.LayoutFieldKey(this.Document)]),
-            docs => {
-                console.log('updated')
-                this.handleFieldUpdate(docs);
-            }
-        );
+        // this.disposers.fieldList = reaction(
+        //     () => DocListCast(this.Document[Doc.LayoutFieldKey(this.Document)]),
+        //     docs => {
+        //         console.log('updated')
+        //         this.handleFieldUpdate(docs);
+        //     }
+        // );
     }
 
     get getSubfields(): Field[] { return this.subfields ?? []; };
@@ -53,6 +57,10 @@ export abstract class Field {
         return fields;
     };
 
+    setSubFields = (fields: Field[]) => {
+        this.subfields = fields;
+    }
+
     get renderedDoc(){ return this.Document };
     get getDimensions() { return this.dimensions };
     get getID() { return this.id };
@@ -69,10 +77,28 @@ export abstract class Field {
     abstract setContent(content: string, type: ViewType): void;
     abstract getContent(): string;
 
+    makeClone = (subfields: boolean = false): Field => {
+        const newSettings: FieldSettings = this.settings;
+        if (!subfields) newSettings.subfields = [];
+        newSettings.opts = this.documentOptions;
+        return this.initField(newSettings, this.id, this.parent, true);
+    }
+
+    @computed get documentOptions(): DocumentOptions {
+        const opts: DocumentOptions = {};
+        Object.assign(opts, this.Document[DocData]);
+        Object.entries(opts).forEach(([key, field]) => {
+            if (field instanceof ObjectField) {
+                Object.assign(opts, {[key]: ObjectField.MakeCopy(field)})
+            } else if (field instanceof ComputedField) {
+                Object.assign(opts, {[key]: field[Copy]()})
+            }
+        })
+        return opts
+    }
+
     changeFieldType = (newType: ViewType): Field => {
-        console.log('changed')
-        this.settings.viewType = newType;
-        const newField: Field = this.initField(this.settings, this.id, this.parent);
+        const newField: Field = this.initField(this.settings, this.id, this.parent, true);
         this.parent.exchangeFields(newField, this);
         return newField;
     }
@@ -82,7 +108,6 @@ export abstract class Field {
     }
 
     addFieldFromDoc = (doc: Doc) => {
-        console.log('add field called');
         const par = this.Document;
         const settings: FieldSettings = {
             tl: [Number(doc._x) / Number(par._width), Number(doc._y) / Number(par._height)],
@@ -95,13 +120,12 @@ export abstract class Field {
         this.subfields.push(newField);
     };
 
-    // addField = (field: Field) => {
-    //     console.log('added')
-    //     if (!this.subfields.includes(field)){
-    //         this.subfields.push(field);
-    //         // Doc.SetContainer(field.Document, this.Document);
-    //     }
-    // }
+    addField = (field: Field) => {
+        if (!this.subfields.includes(field)){
+            this.subfields.push(field);
+            // Doc.SetContainer(field.Document, this.Document);
+        }
+    }
 
     removeField = (field: Field) => {
         // var childDocs: Doc[] = DocListCast(this.Document[Doc.LayoutFieldKey(this.Document)]);
@@ -118,11 +142,11 @@ export abstract class Field {
 
     applyAttributes(field: Field) {
         field.setTitle(this.title);
-        field.initializeDocument(this.Document);
+        field.initializeDocument();
         field.subfields = this.subfields;
     }
 
-    abstract initializeDocument(oldDoc?: Doc): void;
+    abstract initializeDocument(): void;
 
     dispose = () => {
         Object.values(this.disposers).forEach(disposer => disposer?.());
@@ -180,15 +204,15 @@ export abstract class Field {
 
     private applyBasicOpts = (dimensions: FieldDimensions, settings: FieldSettings) => {
         const opts: DocumentOptions = settings.opts;
-        opts.isDefaultTemplateDoc = true;
-        opts._layout_hideScroll = true;
-        opts.x = dimensions.coord.x;
-        opts.y = dimensions.coord.y;
-        opts._height = dimensions.height;
-        opts._width = dimensions.width;
-        opts._nativeWidth = dimensions.width;
-        opts._nativeHeight = dimensions.height;
-        opts._layout_nativeDimEditable = true;
+        opts.isDefaultTemplateDoc ??= true;
+        opts._layout_hideScroll ??= true;
+        opts.x ??= dimensions.coord.x;
+        opts.y ??= dimensions.coord.y;
+        opts._height ??= dimensions.height;
+        opts._width ??= dimensions.width;
+        opts._nativeWidth ??= dimensions.width;
+        opts._nativeHeight ??= dimensions.height;
+        opts._layout_nativeDimEditable ??= true;
     };
 
 }
@@ -219,3 +243,7 @@ export type FieldDimensions = {
     height: number;
     coord: {x: number, y: number};
 }
+
+export type FieldTree = {
+    node: {field: Field, subfields: FieldTree[]}
+}
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
index f3e4130a4..eb12bfef9 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
@@ -5,8 +5,8 @@ import { DecorationField } from "./DecorationField";
 
 export class FieldUtils {
 
-    public static initField = (settings: FieldSettings, index: number, parent: Field): Field => { 
-        const id = Number(`${parent.getID}${index}`);
+    public static initField = (settings: FieldSettings, index: number, parent: Field, sameId: boolean = false): Field => { 
+        const id = sameId ? index : Number(`${parent.getID}${index}`);
         switch (settings.viewType) {
             case ViewType.FREEFORM: case ViewType.CAROUSEL3D:
                 return new DynamicField(settings, id, parent);
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticContentField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticContentField.tsx
index 63fe530a6..8b28d82e1 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticContentField.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticContentField.tsx
@@ -13,12 +13,15 @@ export abstract class StaticContentField extends Field {
     protected content: string = ''; 
     protected subfields: Field[];
 
-    constructor(settings: FieldSettings, parent: Field, id: number) {
+    protected Document: Doc;
+
+    constructor(settings: FieldSettings, id: number, parent: Field) {
         super(settings, id, FieldUtils.initField, parent);
         this.subfields = this.setupSubfields(this);
+        this.Document = this.initializeDocument();
     };
 
-    abstract setContent(content: string, type: ViewType): void;
+    abstract setContent(content: string, type?: ViewType): void;
     getContent = () => { return this.content ?? 'unset'};
     get isContentField(): boolean { return true };
 
@@ -27,15 +30,10 @@ export abstract class StaticContentField extends Field {
 
 export class ImageTemplateField extends StaticContentField {
 
-    protected Document: Doc;
-
-    constructor(settings: FieldSettings, id: number, parent: Field){
-        super(settings, parent, id)
-        this.Document = this.initializeDocument();
-    }
+    setContent = (url: string, type?: ViewType) => { 
+        this.settings.viewType = type ?? this.settings.viewType;
 
-    setContent = (url: string, type: ViewType) => { 
-        if (type === ViewType.IMG){
+        if (type === ViewType.IMG || type === undefined){
             const imgField = new ImageField(url);
             this.Document[DocData]['data'] = imgField;
             this.content = url;
@@ -45,14 +43,11 @@ export class ImageTemplateField extends StaticContentField {
         }
     };
 
-    initializeDocument = (): Doc => {
-        const url = String(this.content);
+    initializeDocument(): Doc {
         this.settings.opts.title = this.title;
         this.settings.opts._layout_fitWidth = false;
 
-        let doc: Doc = Docs.Create.ImageDocument(url, this.settings.opts);
-
-        this.Document = doc;
+        let doc: Doc = Docs.Create.ImageDocument(this.content, this.settings.opts);
 
         return doc;
     };
@@ -60,15 +55,10 @@ export class ImageTemplateField extends StaticContentField {
 
 export class TextTemplateField extends StaticContentField {
 
-    protected Document: Doc;
+    setContent = (text: string, type?: ViewType) => { 
+        this.settings.viewType = type ?? this.settings.viewType;
 
-    constructor(settings: FieldSettings, id: number, parent: Field){
-        super(settings, parent, id)
-        this.Document = this.initializeDocument();
-    }
-
-    setContent = (text: string, type: ViewType) => { 
-        if (type === ViewType.TEXT) {
+        if (type === ViewType.TEXT || type === undefined) {
             const rtf = {
                 doc: {
                     type: 'doc',
@@ -96,17 +86,15 @@ export class TextTemplateField extends StaticContentField {
         }
     };
 
-    initializeDocument = (): Doc => {
+    initializeDocument(): Doc {
         const opts = this.settings.opts;
         const text = this.content;
 
-        // opts._text_fontSize = `${FieldUtils.calculateFontSize(this.dimensions.width, this.dimensions.height, text, true)}`;
+        opts._text_fontSize = `${FieldUtils.calculateFontSize(this.dimensions.width, this.dimensions.height, text, true)}`;
         opts.title = this.title;
 
         let doc: Doc = Docs.Create.TextDocument(text, opts);
 
-        this.Document = doc;
-
         return doc;
     };
 }
\ No newline at end of file
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
index 687b655d1..43f622512 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
@@ -4,11 +4,12 @@ import { Doc, DocListCast, FieldType } from "../../../../../fields/Doc";
 import { Docs } from "../../../../documents/Documents";
 import { Col } from "./DocCreatorMenu";
 import { DynamicField } from "./FieldTypes/DynamicField";
-import { Field, FieldSettings, ViewType } from "./FieldTypes/Field";
+import { Field, FieldSettings, FieldTree, ViewType } from "./FieldTypes/Field";
 import {  } from "./FieldTypes/FieldUtils";
 import { observer } from "mobx-react";
 import { IDisposer } from "mobx-utils";
 import { Width } from "../../../../../fields/DocSymbols";
+import { TemplateLayouts } from "./TemplateBackend";
 
 export class Template {
 
@@ -31,14 +32,22 @@ export class Template {
         //dispose each subfields disposers, etc.
     }
 
-    cloneBase = () => {
-        const clone: Template = new Template(this.settings);
-        this.mainField.applyAttributes(clone.mainField);
-        clone.allFields.filter(field => field !== clone.mainField).forEach(field => {
-            const matchingField: Field = this.allFields.filter(f => f.getID === field.getID)[0];
-            matchingField.applyAttributes(field);
-        })
-        clone.mainField.initializeDocument();
+    cloneBase = (): Template => {
+        const makeCloneFieldTree = (field: Field): Field => {
+            const root: Field = field.makeClone();
+            field.getSubfields.forEach(field => {
+                const clone: Field = makeCloneFieldTree(field);
+                root.addField(clone);
+            });
+            return root;
+        }
+
+        const clone: Template = new Template(TemplateLayouts.BasicSettings);
+        console.log('made clone')
+        clone.mainField = makeCloneFieldTree(this.mainField) as DynamicField;
+        console.log('reinit')
+        clone.mainField.initializeDocument(clone.mainField.documentOptions);
+        console.log('cloned, fieldinfo: ', this.mainField, ' width: ', this.mainField.renderedDoc._width, ' options width: ', clone.mainField.documentOptions._width);
         return clone;
     }
 
-- 
cgit v1.2.3-70-g09d2


From cf91c46cfec6e3e36b9184764016f9c1b5c997d4 Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Tue, 11 Mar 2025 17:31:16 +0100
Subject: c

---
 .../DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx   | 26 ++++++++--------------
 .../DocCreatorMenu/FieldTypes/DynamicField.tsx     | 11 ++++++++-
 .../DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx | 10 +++++++--
 .../FieldTypes/StaticContentField.tsx              |  4 ++++
 .../nodes/DataVizBox/DocCreatorMenu/Template.tsx   | 20 ++++++++---------
 5 files changed, 41 insertions(+), 30 deletions(-)

(limited to 'src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx')

diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
index 099d082d3..6d0155b45 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
@@ -7,7 +7,7 @@ import * as React from 'react';
 import ReactLoading from 'react-loading';
 import { ClientUtils, returnEmptyFilter, returnFalse, returnTrue, setupMoveUpEvents } from '../../../../../ClientUtils';
 import { emptyFunction } from '../../../../../Utils';
-import { Doc, FieldType, NumListCast, StrListCast, returnEmptyDoclist } from '../../../../../fields/Doc';
+import { Doc, DocListCast, FieldType, NumListCast, StrListCast, returnEmptyDoclist } from '../../../../../fields/Doc';
 import { Id } from '../../../../../fields/FieldSymbols';
 import { Cast, DocCast, ImageCast, StrCast } from '../../../../../fields/Types';
 import { ImageField } from '../../../../../fields/URLField';
@@ -34,6 +34,7 @@ import { TemplateManager } from './TemplateManager';
 import { Template } from './Template';
 import { Field, ViewType } from './FieldTypes/Field';
 import { TabDocView } from '../../../collections/TabDocView';
+import { DocData } from '../../../../../fields/DocSymbols';
 
 export enum LayoutType {
     FREEFORM = 'Freeform',
@@ -74,6 +75,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     @observable _GPTOpt: boolean = false;
     @observable _callCount: number = 0;
     @observable _GPTLoading: boolean = false;
+    @observable _DOCCC: Doc | undefined;
 
     @observable _pageX: number = 0;
     @observable _pageY: number = 0;
@@ -623,8 +625,6 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
             const cols = this.fieldsInfos;
             templates.push(...this.templateManager.getValidTemplates(cols));
 
-            console.log(templates)
-
             const assignments: [Template, { [field: number]: Col }][] = await this.assignColsToFields(templates, cols);
 
             const renderedTemplatePromises: Promise<Template | undefined>[] = assignments.map(([template, assignments]) => this.applyGPTContentToTemplate(template, assignments));
@@ -735,12 +735,11 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     
         const processContent = async (content: {[title: string]: string}) => {
 
-            const templateCopy = template.cloneBase(); 
+            const templateCopy = await template.cloneBase(); 
 
             fields.filter(title => title).forEach(title => {
                 const field = templateCopy.getFieldByTitle(title);
                 if (field === undefined) return;
-                console.log('setting content to: ', content[title]);
                 field.setContent(content[title], field.viewType);
             });
     
@@ -765,23 +764,20 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
             await Promise.all(gptPromises);
 
             await Promise.all(imagePromises);
-    
-            return templateCopy.getRenderedDoc();
-        };
 
-        const rows = [1, 2, 3, 4];
+            this._DOCCC = templateCopy.mainField.renderedDoc;
+            return templateCopy.mainField.renderedDoc;
+        };
         
         let docs: Promise<Doc>[];
         if (this.DEBUG_MODE) {
-            docs = rows.map(() => processContent({}));
+            docs = [1, 2, 3, 4].map(() => processContent({}));
         } else {
             docs = rowContents.map(content => processContent(content));
         }
 
         const renderedDocs = await Promise.all(docs);
 
-        //renderedDocs.forEach(doc => {console.log(doc._height, doc._width); doc._height = 400; doc._width = 400});
-
         this._docsRendering = false; // removes loading indicator
 
         return renderedDocs;
@@ -1035,7 +1031,6 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
     applyLayout = (collection: Doc, docs: Doc[]) => {
         const { horizontalSpan, verticalSpan } = this.previewInfo;
-        console.log(this.previewInfo)
         collection._height = verticalSpan;
         collection._width = horizontalSpan;
 
@@ -1088,11 +1083,8 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     @type the type of collection the docs should render to (ie. freeform, carousel, card)
      */
     updateRenderedDocCollection = () => {
-        console.log('called');
         if (!this._fullyRenderedDocs) return;
 
-        //const largerSpan: number = horizontalSpan > verticalSpan ? horizontalSpan : verticalSpan;
-
         const collectionFactory = (): (docs: Doc[], options: DocumentOptions) => Doc => {
             switch (this._layout.type) {
                 case LayoutType.CAROUSEL3D:
@@ -1110,7 +1102,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
             }
         }
 
-        const collection = collectionFactory()(this._fullyRenderedDocs, {
+        const collection = collectionFactory()([this._fullyRenderedDocs[6], this._fullyRenderedDocs[9]], {
             isDefaultTemplateDoc: true,
             title: 'title',
             backgroundColor: 'gray',
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
index c9e76dcbd..bf4f1b0a4 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
@@ -34,9 +34,19 @@ export class DynamicField extends Field {
         return [];
     }
 
+    makeClone = async (subfields: boolean = false): Promise<Field> => {
+        const newSettings: FieldSettings = this.settings;
+        if (!subfields) newSettings.subfields = [];
+        const field: DynamicField = this.initField(newSettings, this.id, this.parent, true) as DynamicField;
+        //field.Document = (await Doc.MakeClone(this.Document)).clone;
+        return field
+    }
+
     initializeDocument = (oldOpts?: DocumentOptions): Doc => {
         let doc: Doc;
+        //this.settings.opts.data = undefined;
         const renderedSubfields: Doc[] = this.subfields.map(field => field.renderedDoc);
+        console.log('fields: ', renderedSubfields)
         this.settings.opts.title = this.title;
         switch (this.settings.viewType) {
             case ViewType.CAROUSEL3D:
@@ -51,7 +61,6 @@ export class DynamicField extends Field {
         }
 
         this.Document = doc;
-        console.log('width: ', doc._width, ' height: ', doc._height, ' id: ', this.idd)
         return doc;
     }
 
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
index afdbeeadd..06b364254 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
@@ -12,6 +12,7 @@ import { DocData } from "../../../../../../fields/DocSymbols";
 import { ObjectField } from "../../../../../../fields/ObjectField";
 import { ComputedField } from "../../../../../../fields/ScriptField";
 import { Copy } from "../../../../../../fields/FieldSymbols";
+import { OmitKeys } from "../../../../../../ClientUtils";
 
 export abstract class Field {
 
@@ -77,11 +78,15 @@ export abstract class Field {
     abstract setContent(content: string, type: ViewType): void;
     abstract getContent(): string;
 
-    makeClone = (subfields: boolean = false): Field => {
+    makeClone = async (subfields: boolean = false): Promise<Field> => {
         const newSettings: FieldSettings = this.settings;
         if (!subfields) newSettings.subfields = [];
         newSettings.opts = this.documentOptions;
-        return this.initField(newSettings, this.id, this.parent, true);
+        newSettings.title = this.title;
+        console.log('settings: ', newSettings.opts)
+        const field: Field = this.initField(newSettings, this.id, this.parent, true);
+        //field.Document = (await Doc.MakeClone(this.Document)).clone;
+        return field
     }
 
     @computed get documentOptions(): DocumentOptions {
@@ -123,6 +128,7 @@ export abstract class Field {
     addField = (field: Field) => {
         if (!this.subfields.includes(field)){
             this.subfields.push(field);
+            console.log('field added')
             // Doc.SetContainer(field.Document, this.Document);
         }
     }
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticContentField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticContentField.tsx
index 8b28d82e1..18b72e4ea 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticContentField.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticContentField.tsx
@@ -7,6 +7,7 @@ import { ImageField } from "../../../../../../fields/URLField";
 import { ViewComponentType } from "@fullcalendar/core";
 import { DynamicField } from "./DynamicField";
 import { FieldUtils } from "./FieldUtils";
+import { random } from "lodash";
 
 export abstract class StaticContentField extends Field {
 
@@ -15,10 +16,13 @@ export abstract class StaticContentField extends Field {
 
     protected Document: Doc;
 
+    protected idd: number;
+
     constructor(settings: FieldSettings, id: number, parent: Field) {
         super(settings, id, FieldUtils.initField, parent);
         this.subfields = this.setupSubfields(this);
         this.Document = this.initializeDocument();
+        this.idd = random(0, 1000);
     };
 
     abstract setContent(content: string, type?: ViewType): void;
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
index 43f622512..0f911421a 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
@@ -32,22 +32,22 @@ export class Template {
         //dispose each subfields disposers, etc.
     }
 
-    cloneBase = (): Template => {
-        const makeCloneFieldTree = (field: Field): Field => {
-            const root: Field = field.makeClone();
-            field.getSubfields.forEach(field => {
-                const clone: Field = makeCloneFieldTree(field);
+    cloneBase = async (): Promise<Template> => {
+        const makeCloneFieldTree = async (field: Field): Promise<Field> => {
+            const root: Field = await field.makeClone();
+            field.getSubfields.forEach(async field => {
+                const clone: Field = await makeCloneFieldTree(field);
                 root.addField(clone);
             });
             return root;
         }
 
         const clone: Template = new Template(TemplateLayouts.BasicSettings);
-        console.log('made clone')
-        clone.mainField = makeCloneFieldTree(this.mainField) as DynamicField;
-        console.log('reinit')
-        clone.mainField.initializeDocument(clone.mainField.documentOptions);
-        console.log('cloned, fieldinfo: ', this.mainField, ' width: ', this.mainField.renderedDoc._width, ' options width: ', clone.mainField.documentOptions._width);
+        clone.mainField = await makeCloneFieldTree(this.mainField) as DynamicField;
+        console.log('last init')
+        clone.mainField.initializeDocument();
+        clone.mainField.renderedDoc._width = this.mainField.renderedDoc._width;
+        clone.mainField.renderedDoc._height = this.mainField.renderedDoc._height;
         return clone;
     }
 
-- 
cgit v1.2.3-70-g09d2


From 5a926baa62489d5aa5134f8e5e08cfcb236102c2 Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Tue, 11 Mar 2025 17:43:27 +0100
Subject: c

---
 .../nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticContentField.tsx | 2 +-
 src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx         | 4 ----
 2 files changed, 1 insertion(+), 5 deletions(-)

(limited to 'src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx')

diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticContentField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticContentField.tsx
index 18b72e4ea..736f144cd 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticContentField.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticContentField.tsx
@@ -94,7 +94,7 @@ export class TextTemplateField extends StaticContentField {
         const opts = this.settings.opts;
         const text = this.content;
 
-        opts._text_fontSize = `${FieldUtils.calculateFontSize(this.dimensions.width, this.dimensions.height, text, true)}`;
+        opts.text_fontSize = `${FieldUtils.calculateFontSize(this.dimensions.width, this.dimensions.height, text, true)}`;
         opts.title = this.title;
 
         let doc: Doc = Docs.Create.TextDocument(text, opts);
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
index bdfedbdc9..b0f8a522c 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
@@ -1,13 +1,9 @@
-import { Doc, FieldType } from "../../../../../fields/Doc";
-
 import { makeAutoObservable, reaction } from "mobx";
 import { Doc, DocListCast, FieldType } from "../../../../../fields/Doc";
 import { Docs } from "../../../../documents/Documents";
 import { Col } from "./DocCreatorMenu";
 import { DynamicField } from "./FieldTypes/DynamicField";
 import { Field, FieldSettings, FieldTree, ViewType } from "./FieldTypes/Field";
-import {  } from "./FieldTypes/FieldUtils";
-import { } from "./FieldTypes/StaticField";
 import { TemplateLayouts } from "./TemplateBackend";
 
 export class Template {
-- 
cgit v1.2.3-70-g09d2


From 1ffa8a8fb3e16bd5a3338d18782ddda0c2ffca03 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sun, 16 Mar 2025 21:15:00 -0400
Subject: a lot of code cleanup for doc creators templates

---
 src/client/views/Main.tsx                          |   6 +-
 .../DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx   |  89 ++-
 .../DocCreatorMenu/FieldTypes/DecorationField.tsx  |   3 -
 .../DocCreatorMenu/FieldTypes/DynamicField.tsx     | 189 -----
 .../DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx | 167 -----
 .../DocCreatorMenu/FieldTypes/FieldUtils.tsx       |  64 --
 .../FieldTypes/StaticContentField.tsx              |  90 ---
 .../nodes/DataVizBox/DocCreatorMenu/Template.ts    | 138 ++++
 .../nodes/DataVizBox/DocCreatorMenu/Template.tsx   | 139 ----
 .../DataVizBox/DocCreatorMenu/TemplateBackend.ts   | 768 ++++++++++++++++++++
 .../DataVizBox/DocCreatorMenu/TemplateBackend.tsx  | 771 ---------------------
 .../TemplateFieldTypes/DecorationField.ts          |  11 +
 .../TemplateFieldTypes/DynamicField.ts             | 164 +++++
 .../TemplateFieldTypes/StaticContentField.ts       |  72 ++
 .../TemplateFieldTypes/TemplateField.ts            | 159 +++++
 .../TemplateFieldTypes/TemplateFieldUtils.ts       |  71 ++
 .../DataVizBox/DocCreatorMenu/TemplateManager.ts   |  33 +
 .../DataVizBox/DocCreatorMenu/TemplateManager.tsx  |  34 -
 18 files changed, 1461 insertions(+), 1507 deletions(-)
 delete mode 100644 src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DecorationField.tsx
 delete mode 100644 src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
 delete mode 100644 src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
 delete mode 100644 src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
 delete mode 100644 src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticContentField.tsx
 create mode 100644 src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.ts
 delete mode 100644 src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
 create mode 100644 src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.ts
 delete mode 100644 src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
 create mode 100644 src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/DecorationField.ts
 create mode 100644 src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/DynamicField.ts
 create mode 100644 src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/StaticContentField.ts
 create mode 100644 src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/TemplateField.ts
 create mode 100644 src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/TemplateFieldUtils.ts
 create mode 100644 src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.ts
 delete mode 100644 src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.tsx

(limited to 'src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx')

diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx
index fc2d7f572..b335432c9 100644
--- a/src/client/views/Main.tsx
+++ b/src/client/views/Main.tsx
@@ -65,8 +65,8 @@ import { PresBox, PresElementBox } from './nodes/trails';
 import { FaceRecognitionHandler } from './search/FaceRecognitionHandler';
 import { SearchBox } from './search/SearchBox';
 import { StickerPalette } from './smartdraw/StickerPalette';
-import { Field } from './nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field';
-import { FieldUtils } from './nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils';
+import { TemplateField } from './nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/TemplateField';
+import { TemplateFieldUtils } from './nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/TemplateFieldUtils';
 
 dotenv.config();
 
@@ -102,7 +102,7 @@ FieldLoader.ServerLoadStatus = { requested: 0, retrieved: 0, message: 'cache' };
         new PingManager();
         new KeyManager();
         new FaceRecognitionHandler();
-        Field.initField = FieldUtils.initField; // set the init function for fields
+        TemplateField.initField = TemplateFieldUtils.initField; // set the init function for fields
 
         // initialize plugins and classes that require plugins
         CollectionDockingView.Init(TabDocView);
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
index a702218b0..97faf01c2 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
@@ -27,7 +27,7 @@ import { DocumentView, DocumentViewInternal } from '../../DocumentView';
 import { OpenWhere } from '../../OpenWhere';
 import { DataVizBox } from '../DataVizBox';
 import './DocCreatorMenu.scss';
-import { Field, ViewType } from './FieldTypes/Field';
+import { TemplateField, ViewType } from './TemplateFieldTypes/TemplateField';
 import { Template } from './Template';
 import { TemplateFieldSize, TemplateFieldType, TemplateLayouts } from './TemplateBackend';
 import { TemplateManager } from './TemplateManager';
@@ -371,7 +371,7 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
     }
 
     @action updateRenderedPreviewCollection = async (template: Template) => {
-        this._fullyRenderedDocs = (await this.createDocsFromTemplate(template)) ?? [];
+        this._fullyRenderedDocs = ((await this.createDocsFromTemplate(template)) ?? []).filter(doc => doc).map(doc => doc!);
         console.log(this._fullyRenderedDocs);
         this.updateRenderedDocCollection();
     };
@@ -630,7 +630,7 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
             await Promise.all(renderedTemplatePromises);
         }
 
-        templates.forEach(template => template.mainField.initializeDocument({ subfields: [], title: template.title, opts: {}, viewType: ViewType.FREEFORM, tl: [0, 0], br: [900, 900] }));
+        templates.forEach(template => template.mainField.initializeDocument({ title: template.title, opts: {}, viewType: ViewType.FREEFORM, tl: [0, 0], br: [900, 900] }, []));
 
         setTimeout(() => {
             this.setSuggestedTemplates(templates);
@@ -638,10 +638,10 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
         });
     };
 
-    renderGPTImageCall = async (template: Template, col: Col, fieldNumber: number): Promise<boolean> => {
+    renderGPTImageCall = async (template: Template, col: Col, fieldNumber: number | undefined): Promise<boolean> => {
         const generateAndLoadImage = async (fieldNum: string, column: Col, prompt: string) => {
             const url = await this.generateGPTImage(prompt);
-            const field: Field = template.getFieldByID(Number(fieldNum));
+            const field: TemplateField = template.getFieldByID(Number(fieldNum));
 
             field.setContent(url ?? '', ViewType.IMG);
             field.setTitle(col.title);
@@ -665,7 +665,7 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
         return true;
     };
 
-    renderGPTTextCall = async (template: Template, col: Col, fieldNum: number): Promise<boolean> => {
+    renderGPTTextCall = async (template: Template, col: Col, fieldNum: number | undefined): Promise<boolean> => {
         const wordLimit = (size: TemplateFieldSize) => {
             switch (size) {
                 case TemplateFieldSize.TINY:
@@ -697,7 +697,7 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
             if (res) {
                 const assignments: { [title: string]: { number: string; content: string } } = JSON.parse(res);
                 Object.entries(assignments).forEach(([, /* title */ info]) => {
-                    const field: Field = template.getFieldByID(Number(info.number));
+                    const field: TemplateField = template.getFieldByID(Number(info.number));
                     // const column = this.getColByTitle(title);
 
                     field.setContent(info.content ?? '', ViewType.TEXT);
@@ -771,7 +771,7 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
             return templateCopy.mainField.renderedDoc;
         };
 
-        let docs: Promise<Doc>[];
+        let docs: Promise<Doc | undefined>[];
         if (this.DEBUG_MODE) {
             docs = [1, 2, 3, 4].map(() => processContent({}));
         } else {
@@ -868,30 +868,31 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
     get templatesPreviewContents() {
         const GPTOptions = <div></div>;
 
-        const previewDoc = (doc: Doc, template: Template) => (
-            <DocumentView
-                Document={doc}
-                isContentActive={emptyFunction} // !!! should be return false
-                addDocument={returnFalse}
-                moveDocument={returnFalse}
-                removeDocument={returnFalse}
-                PanelWidth={() => (this._selectedTemplate === template ? 104 : 111)}
-                PanelHeight={() => (this._selectedTemplate === template ? 104 : 111)}
-                ScreenToLocalTransform={() => new Transform(-this._pageX - 5, -this._pageY - 35, 1)}
-                renderDepth={1}
-                whenChildContentsActiveChanged={emptyFunction}
-                focus={emptyFunction}
-                styleProvider={DefaultStyleProvider}
-                addDocTab={this._props.addDocTab}
-                pinToPres={() => undefined}
-                childFilters={returnEmptyFilter}
-                childFiltersByRanges={returnEmptyFilter}
-                searchFilterDocs={returnEmptyDoclist}
-                fitContentsToBox={returnFalse}
-                fitWidth={returnFalse}
-                hideDecorations={true}
-            />
-        );
+        const previewDoc = (doc: Doc | undefined, template: Template) =>
+            !doc ? null : (
+                <DocumentView
+                    Document={doc}
+                    isContentActive={emptyFunction} // !!! should be return false
+                    addDocument={returnFalse}
+                    moveDocument={returnFalse}
+                    removeDocument={returnFalse}
+                    PanelWidth={() => (this._selectedTemplate === template ? 104 : 111)}
+                    PanelHeight={() => (this._selectedTemplate === template ? 104 : 111)}
+                    ScreenToLocalTransform={() => new Transform(-this._pageX - 5, -this._pageY - 35, 1)}
+                    renderDepth={1}
+                    whenChildContentsActiveChanged={emptyFunction}
+                    focus={emptyFunction}
+                    styleProvider={DefaultStyleProvider}
+                    addDocTab={this._props.addDocTab}
+                    pinToPres={() => undefined}
+                    childFilters={returnEmptyFilter}
+                    childFiltersByRanges={returnEmptyFilter}
+                    searchFilterDocs={returnEmptyDoclist}
+                    fitContentsToBox={returnFalse}
+                    fitWidth={returnFalse}
+                    hideDecorations={true}
+                />
+            );
 
         //<img className='docCreatorMenu-preview-image expanded' src={this._expandedPreview.icon!.url.href.replace(".png", "_o.png")} />
 
@@ -1096,19 +1097,13 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
 
         const collectionFactory = (): ((docs: Doc[], options: DocumentOptions) => Doc) => {
             switch (this._layout.type) {
-                case LayoutType.CAROUSEL3D:
-                    return Docs.Create.Carousel3DDocument;
-                case LayoutType.FREEFORM:
-                    return Docs.Create.FreeformDocument;
-                case LayoutType.CARD:
-                    return Docs.Create.CardDeckDocument;
-                case LayoutType.MASONRY:
-                    return Docs.Create.MasonryDocument;
-                case LayoutType.CAROUSEL:
-                    return Docs.Create.CarouselDocument;
-                default:
-                    return Docs.Create.FreeformDocument;
-            }
+                case LayoutType.CAROUSEL3D: return Docs.Create.Carousel3DDocument;
+                case LayoutType.FREEFORM:   return Docs.Create.FreeformDocument;
+                case LayoutType.CARD:       return Docs.Create.CardDeckDocument;
+                case LayoutType.MASONRY:    return Docs.Create.MasonryDocument;
+                case LayoutType.CAROUSEL:   return Docs.Create.CarouselDocument;
+                default:                    return Docs.Create.FreeformDocument;
+            } // prettier-ignore
         };
 
         const collection = collectionFactory()(this._fullyRenderedDocs, {
@@ -1241,9 +1236,9 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
                                 emptyFunction,
                                 undoable(clickEv => {
                                     clickEv.stopPropagation();
-                                    if (!this._selectedTemplate) return;
+                                    if (!this._selectedTemplate || !this._selectedTemplate.getRenderedDoc()) return;
                                     const layout: DataVizTemplateLayout = {
-                                        template: this._selectedTemplate.getRenderedDoc(),
+                                        template: this._selectedTemplate.getRenderedDoc()!,
                                         layout: { type: this._layout.type, xMargin: this._layout.xMargin, yMargin: this._layout.yMargin, repeat: 0 },
                                         columns: this.columnsCount,
                                         rows: this.rowsCount,
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DecorationField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DecorationField.tsx
deleted file mode 100644
index 98a9dc7a6..000000000
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DecorationField.tsx
+++ /dev/null
@@ -1,3 +0,0 @@
-import { DynamicField } from './DynamicField';
-
-export class DecorationField extends DynamicField {}
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
deleted file mode 100644
index f100830d3..000000000
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
+++ /dev/null
@@ -1,189 +0,0 @@
-import { Doc, DocListCast } from '../../../../../../fields/Doc';
-import { Docs } from '../../../../../documents/Documents';
-import { Field, FieldSettings, ViewType } from './Field';
-import { List } from '../../../../../../fields/List';
-import { DocData } from '../../../../../../fields/DocSymbols';
-import { DocumentType } from '../../../../../documents/DocumentTypes';
-import { reaction } from 'mobx';
-import { IDisposer } from 'mobx-utils';
-
-export class DynamicField extends Field {
-    protected subfields!: Field[];
-
-    protected disposers: { [name: string]: IDisposer } = {};
-    init(settings: FieldSettings, id: number, parent?: DynamicField) {
-        super.baseinit(undefined as unknown as Doc, settings, parent, id);
-        const { doc, subFields } = this.initializeDocument(settings);
-        this.Document = doc;
-        this.subfields = subFields;
-
-        this.disposers.fieldList = reaction(
-            () => DocListCast(this.Document[Doc.LayoutFieldKey(this.Document)]),
-            docs => {
-                console.log('updated');
-                this.handleFieldUpdate(docs);
-            }
-        );
-        return this;
-    }
-
-    static setupSubfields(subFieldSettings: FieldSettings[] | undefined, parent?: DynamicField): Field[] {
-        return subFieldSettings?.map((fieldSettings, index) => Field.initField!(fieldSettings, index, parent)) || [];
-    }
-
-    get getSubfields(): Field[] {
-        return this.subfields ?? [];
-    }
-    get getAllSubfields() {
-        let fields: Field[] = [];
-        this.subfields?.forEach(field => {
-            fields.push(field);
-            fields = fields.concat(field instanceof DynamicField ? field.getAllSubfields : ([] as Field[]));
-        });
-        return fields;
-    }
-
-    setSubFields = (fields: Field[]) => {
-        this.subfields = fields;
-    };
-    handleFieldUpdate = (newDocsList: Doc[]) => {
-        const currRenderedDocs: Set<Doc> = new Set();
-        this.subfields.forEach(field => currRenderedDocs.add(field.Document));
-        newDocsList.forEach(doc => {
-            if (!currRenderedDocs.has(doc)) {
-                this.addFieldFromDoc(doc);
-            }
-        });
-        currRenderedDocs.forEach(doc => {
-            if (!newDocsList.includes(doc)) {
-                const fields = this.subfields.filter(field => field.Document === doc);
-                fields.forEach(field => this.removeField(field));
-            }
-        });
-    };
-
-    addFieldFromDoc = (doc: Doc) => {
-        const par = this.Document;
-        const settings: FieldSettings = {
-            tl: [Number(doc._x) / Number(par._width), Number(doc._y) / Number(par._height)],
-            br: [(Number(doc._x) + Number(doc._width)) / Number(par._width), (Number(doc._y) + Number(doc._height)) / Number(par._height)],
-            viewType: doc.type === DocumentType.COL ? ViewType.FREEFORM : ViewType.STATIC,
-            opts: {},
-        };
-
-        const newField: Field = Field.initField!(settings, this.subfields.length, this);
-        this.subfields.push(newField);
-    };
-
-    addField = (field: Field) => {
-        if (!this.subfields.includes(field)) {
-            this.subfields.push(field);
-            console.log('field added');
-            // Doc.SetContainer(field.Document, this.Document);
-        }
-    };
-
-    dispose = () => {
-        Object.values(this.disposers).forEach(disposer => disposer?.());
-    };
-
-    removeField = (field: Field) => {
-        // var childDocs: Doc[] = DocListCast(this.Document[Doc.LayoutFieldKey(this.Document)]);
-        // this.Document[Doc.LayoutFieldKey(this.Document)] = new List<Doc>([...childDocs.splice(childDocs.indexOf(field.Document), 1)]);
-        this.subfields.splice(this.subfields.indexOf(field), 1);
-        field instanceof DynamicField && field.dispose();
-    };
-
-    exchangeFields = (newField: Field, oldField: Field) => {
-        this.subfields.splice(this.subfields.indexOf(oldField), 1, newField);
-        // this.renderedDoc.
-    };
-    // eslint-disable-next-line @typescript-eslint/no-unused-vars
-    setContent = (content: string, type: ViewType) => {
-        return;
-    };
-    getContent = () => {
-        return '';
-    };
-    get isContentField(): boolean {
-        return false;
-    }
-
-    addChildToDocument = (doc: Doc) => {
-        Doc.SetContainer(doc, this.Document);
-    };
-
-    matches = (): Array<number> => {
-        return [];
-    };
-
-    async makeClone(parent?: DynamicField): Promise<Field> {
-        const field = (await super.makeClone(parent)) as unknown as DynamicField;
-        field.subfields = await Promise.all(this.subfields.map(async cloneField => await cloneField.makeClone(field)));
-        field.Document[DocData].data = new List<Doc>(field.subfields.map(subfield => subfield.renderedDoc));
-        return field;
-    }
-    initializeDocument = (settings: FieldSettings) => {
-        const subFields = DynamicField.setupSubfields(settings.subfields, this);
-        const renderedSubfields = subFields.map(field => field.renderedDoc);
-        settings.opts.title = settings.title;
-        switch (settings.viewType) {
-            case ViewType.CAROUSEL3D:
-                return { doc: Docs.Create.Carousel3DDocument(renderedSubfields, settings.opts), subFields };
-            case ViewType.FREEFORM:
-                return { doc: Docs.Create.FreeformDocument(renderedSubfields, settings.opts), subFields };
-            default:
-                return { doc: Docs.Create.FreeformDocument(renderedSubfields, settings.opts), subFields };
-        }
-    };
-}
-
-// export class DynamicField extends Field {
-//     protected subfields: Field[];
-
-//     protected Document!: Doc;
-
-//     constructor(settings: FieldSettings, id: number, parent?: Field) {
-//         super(settings, id, parent);
-//         this.subfields = this.setupSubfields(this);
-//         this.initializeDocument();
-//     }
-
-//     setContent = (content: string, type: ViewType) => { return };
-//     getContent = () => { return '' };
-//     get isContentField(): boolean { return false };
-
-//     addChildToDocument = (doc: Doc) => {
-//         Doc.SetContainer(doc, this.Document);
-//     }
-
-//     matches = (cols: Col[]): Array<number> => {
-//         return [];
-//     }
-
-//     initializeDocument = (): Doc => {
-//         let doc: Doc;
-//         const renderedSubfields: Doc[] = this.subfields.map(field => field.renderedDoc);
-//         switch (this.settings.viewType) {
-//             case ViewType.CAROUSEL3D:
-//                 doc = Docs.Create.Carousel3DDocument(renderedSubfields, {
-//                     title: this.title,
-//                 });
-//                 break;
-//             case ViewType.FREEFORM:
-//                 doc = Docs.Create.FreeformDocument(renderedSubfields, {
-//                     title: this.title,
-//                 });
-//                 break;
-//             default:
-//                 doc = Docs.Create.FreeformDocument(renderedSubfields, {
-//                     title: this.title,
-//                 });
-//             break;
-//         }
-
-//         this.Document = doc;
-//         return doc;
-//     }
-
-// }
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
deleted file mode 100644
index 111ad8328..000000000
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
+++ /dev/null
@@ -1,167 +0,0 @@
-/* eslint-disable @typescript-eslint/no-explicit-any */
-/* eslint-disable no-use-before-define */
-import { computed } from 'mobx';
-import { Doc } from '../../../../../../fields/Doc';
-import { DocData } from '../../../../../../fields/DocSymbols';
-import { Copy } from '../../../../../../fields/FieldSymbols';
-import { ObjectField } from '../../../../../../fields/ObjectField';
-import { ComputedField } from '../../../../../../fields/ScriptField';
-import { DocumentOptions } from '../../../../../documents/Documents';
-import { Col } from '../DocCreatorMenu';
-import { TemplateFieldSize, TemplateFieldType } from '../TemplateBackend';
-
-export abstract class Field {
-    Document!: Doc;
-
-    static initField?: (settings: FieldSettings, index: number, parent: any /* DynamicField */ | undefined, sameId?: boolean) => Field = undefined;
-
-    protected parent?: any;
-    protected id!: number;
-    settings!: FieldSettings;
-    protected title: string = '';
-    dimensions!: FieldDimensions;
-
-    constructor() {}
-
-    baseinit(doc: Doc, settings: FieldSettings, parent?: any, id: number = 1) {
-        this.id = id;
-        this.Document = doc;
-        this.parent = parent;
-        this.settings = settings;
-        this.title = settings.title ?? '';
-        this.dimensions = this.getLocalDimensions({ tl: this.settings.tl, br: this.settings.br }, this.parent?.getDimensions);
-        this.applyBasicOpts(this.dimensions, settings);
-        return this;
-    }
-
-    get renderedDoc() {
-        return this.Document;
-    }
-    get getDimensions() {
-        return this.dimensions;
-    }
-    get getID() {
-        return this.id;
-    }
-    get getDescription(): string {
-        return this.settings.description ?? '';
-    }
-    get viewType(): ViewType {
-        return this.settings.viewType;
-    }
-
-    setTitle = (title: string) => {
-        this.title = title;
-        this.Document.title = title;
-    };
-    getTitle = () => {
-        return this.title;
-    };
-
-    abstract get isContentField(): boolean;
-    abstract setContent(content: string, type: ViewType): void;
-    abstract getContent(): string;
-
-    async makeClone(parent?: any /* DynamicField*/): Promise<Field> {
-        const field = Field.initField!(this.settings, this.id, parent, true); // create a value for this.Document/subfields that we want to ignore
-        field.Document = (await Doc.MakeClone(this.Document)).clone;
-        field.title = this.title;
-        field.dimensions = this.dimensions;
-        return field;
-    }
-
-    @computed get documentOptions(): DocumentOptions {
-        const opts: DocumentOptions = {};
-        Object.assign(opts, this.Document[DocData]);
-        Object.entries(opts).forEach(([key, field]) => {
-            if (field instanceof ObjectField) {
-                Object.assign(opts, { [key]: ObjectField.MakeCopy(field) });
-            } else if (field instanceof ComputedField) {
-                Object.assign(opts, { [key]: field[Copy]() });
-            }
-        });
-        return opts;
-    }
-
-    // eslint-disable-next-line @typescript-eslint/no-unused-vars
-    changeFieldType = (newType: ViewType): Field => {
-        const newField = Field.initField!(this.settings, this.id, this.parent, true);
-        this.parent?.exchangeFields(newField, this);
-        return newField;
-    };
-
-    matches = (cols: Col[]): number[] => {
-        const colMatchesField = (col: Col) => {
-            const isMatch: boolean = (this.settings.sizes?.some(size => col.sizes?.includes(size)) && this.settings.types?.includes(col.type)) ?? false;
-            return isMatch;
-        };
-
-        const matches: Array<number> = [];
-
-        cols.forEach((col, v) => {
-            if (colMatchesField(col)) {
-                matches.push(v);
-            }
-        });
-
-        return matches;
-    };
-
-    private getLocalDimensions = (coords: { tl: [number, number]; br: [number, number] }, parentDimensions?: FieldDimensions): FieldDimensions => {
-        if (!parentDimensions) {
-            return { width: coords.br[0] - coords.tl[0], height: coords.br[1] - coords.tl[1], coord: { x: coords.tl[0], y: coords.tl[1] } };
-        }
-        const l = (coords.tl[0] * parentDimensions.width) / 2;
-        const t = coords.tl[1] * parentDimensions.height / 2; //prettier-ignore
-        const r = (coords.br[0] * parentDimensions.width) / 2;
-        const b = coords.br[1] * parentDimensions.height / 2; //prettier-ignore
-        const width = r - l;
-        const height = b - t;
-        const coord = { x: l, y: t };
-        return { width, height, coord };
-    };
-
-    private applyBasicOpts = (dimensions: FieldDimensions, settings: FieldSettings) => {
-        const opts: DocumentOptions = settings.opts;
-        opts.isDefaultTemplateDoc ??= true;
-        opts._layout_hideScroll ??= true;
-        opts.x ??= dimensions.coord.x;
-        opts.y ??= dimensions.coord.y;
-        opts._height ??= dimensions.height;
-        opts._width ??= dimensions.width;
-        opts._nativeWidth ??= dimensions.width;
-        opts._nativeHeight ??= dimensions.height;
-        opts._layout_nativeDimEditable ??= true;
-    };
-}
-
-export type FieldSettings = {
-    tl: [number, number];
-    br: [number, number];
-    opts: DocumentOptions;
-    viewType: ViewType;
-    title?: string;
-    subfields?: FieldSettings[];
-    types?: TemplateFieldType[];
-    sizes?: TemplateFieldSize[];
-    description?: string;
-};
-
-export enum ViewType {
-    CAROUSEL3D = 'carousel3d',
-    FREEFORM = 'freeform',
-    STATIC = 'static',
-    DEC = 'decoration',
-    IMG = 'image',
-    TEXT = 'text',
-}
-
-export type FieldDimensions = {
-    width: number;
-    height: number;
-    coord: { x: number; y: number };
-};
-
-export type FieldTree = {
-    node: { field: Field; subfields: FieldTree[] };
-};
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
deleted file mode 100644
index 0582c9ed3..000000000
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
+++ /dev/null
@@ -1,64 +0,0 @@
-import { Field, FieldSettings, ViewType } from './Field';
-import { TextTemplateField, ImageTemplateField } from './StaticContentField';
-import { DecorationField } from './DecorationField';
-import { DynamicField } from './DynamicField';
-
-export class FieldUtils {
-    public static initField = (settings: FieldSettings, index: number, parent: DynamicField | undefined, sameId: boolean = false): Field => {
-        const id = sameId ? index : parent ? Number(`${parent.getID}${index}`) : 1;
-        switch (settings.viewType) {
-            case ViewType.FREEFORM:
-            case ViewType.CAROUSEL3D:
-                return new DynamicField().init(settings, id, parent);
-            case ViewType.IMG:
-                return new ImageTemplateField().init(settings, id, parent);
-            case ViewType.TEXT:
-                return new TextTemplateField().init(settings, id, parent);
-            case ViewType.DEC:
-                return new DecorationField().init(settings, id, parent);
-        }
-        return new TextTemplateField().init(settings, id, parent);
-    };
-
-    // eslint-disable-next-line @typescript-eslint/no-unused-vars
-    public static calculateFontSize = (contWidth: number, contHeight: number, text: string, uppercase: boolean): number => {
-        const words: string[] = text.split(/\s+/).filter(Boolean);
-
-        let currFontSize = 1;
-        let rowsCount = 1;
-        let currTextHeight = currFontSize * rowsCount * 2;
-
-        while (currTextHeight <= contHeight) {
-            let wordIndex = 0;
-            let currentRowWidth = 0;
-            let wordsInCurrRow = 0;
-            rowsCount = 1;
-
-            while (wordIndex < words.length) {
-                const word = words[wordIndex];
-                const wordWidth = word.length * currFontSize * 0.7;
-
-                if (currentRowWidth + wordWidth <= contWidth) {
-                    currentRowWidth += wordWidth;
-                    ++wordsInCurrRow;
-                } else {
-                    if (words.length !== 1 && words.length > wordsInCurrRow) {
-                        rowsCount++;
-                        currentRowWidth = wordWidth;
-                        wordsInCurrRow = 1;
-                    } else {
-                        break;
-                    }
-                }
-
-                wordIndex++;
-            }
-
-            currTextHeight = rowsCount * currFontSize * 2;
-
-            currFontSize += 1;
-        }
-
-        return currFontSize - 1;
-    };
-}
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticContentField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticContentField.tsx
deleted file mode 100644
index 75aea5440..000000000
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticContentField.tsx
+++ /dev/null
@@ -1,90 +0,0 @@
-import { DocData } from '../../../../../../fields/DocSymbols';
-import { RichTextField } from '../../../../../../fields/RichTextField';
-import { ImageField } from '../../../../../../fields/URLField';
-import { Docs } from '../../../../../documents/Documents';
-import { Field, FieldSettings, ViewType } from './Field';
-import { FieldUtils } from './FieldUtils';
-import { DynamicField } from './DynamicField';
-
-export abstract class StaticContentField extends Field {
-    protected content: string = '';
-
-    abstract setContent(content: string, type?: ViewType): void;
-    getContent = () => {
-        return this.content ?? 'unset';
-    };
-    get isContentField(): boolean {
-        return true;
-    }
-}
-
-export class ImageTemplateField extends StaticContentField {
-    init(settings: FieldSettings, id: number, parent: DynamicField | undefined) {
-        super.baseinit(this.initializeDocument(settings), settings, parent, id);
-        return this;
-    }
-
-    setContent = (url: string, type?: ViewType) => {
-        this.settings.viewType = type ?? this.settings.viewType;
-
-        if (type === ViewType.IMG || type === undefined) {
-            const imgField = new ImageField(url);
-            this.Document[DocData].data = imgField;
-            this.content = url;
-        } else {
-            const updatedField = this.changeFieldType(type);
-            updatedField.setContent(url, type);
-        }
-    };
-
-    initializeDocument = (settings: FieldSettings) => {
-        settings.opts.title = settings.title;
-        settings.opts._layout_fitWidth = false;
-
-        return Docs.Create.ImageDocument('', settings.opts);
-    };
-}
-
-export class TextTemplateField extends StaticContentField {
-    init(settings: FieldSettings, id: number, parent?: DynamicField) {
-        super.baseinit(this.initializeDocument(settings), settings, parent, id);
-        this.Document.text_fontSize = `${FieldUtils.calculateFontSize(this.dimensions.width, this.dimensions.height, '', true)}`;
-        return this;
-    }
-    setContent = (text: string, type?: ViewType) => {
-        this.settings.viewType = type ?? this.settings.viewType;
-
-        if (type === ViewType.TEXT || type === undefined) {
-            const rtf = {
-                doc: {
-                    type: 'doc',
-                    content: [
-                        {
-                            type: 'paragraph',
-                            content: [
-                                {
-                                    type: 'text',
-                                    text,
-                                },
-                            ],
-                        },
-                    ],
-                },
-                selection: { type: 'text', anchor: 1, head: 1 },
-                storedMarks: [],
-            };
-            this.content = text;
-            const field = new RichTextField(JSON.stringify(rtf), text);
-            this.Document[DocData]['text'] = field;
-        } else {
-            const updatedField = this.changeFieldType(type);
-            updatedField.setContent(text, type);
-        }
-    };
-
-    initializeDocument = (settings: FieldSettings) => {
-        const opts = settings.opts;
-        opts.title = settings.title;
-        return Docs.Create.TextDocument('', opts);
-    };
-}
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.ts b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.ts
new file mode 100644
index 000000000..ef6867e32
--- /dev/null
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.ts
@@ -0,0 +1,138 @@
+import { makeAutoObservable } from 'mobx';
+import { Col } from './DocCreatorMenu';
+import { DynamicField } from './TemplateFieldTypes/DynamicField';
+import { TemplateField, FieldSettings } from './TemplateFieldTypes/TemplateField';
+import { TemplateLayouts } from './TemplateBackend';
+
+export class Template {
+    mainField: DynamicField;
+    private settings: FieldSettings;
+
+    constructor(templateInfo: FieldSettings) {
+        makeAutoObservable(this);
+        this.settings = templateInfo;
+        this.mainField = this.setupMainField(templateInfo);
+    }
+
+    get childFields(): TemplateField[] {
+        return this.mainField.getSubfields;
+    }
+    get allFields(): TemplateField[] {
+        return this.mainField.getAllSubfields;
+    }
+    get contentFields(): TemplateField[] {
+        return this.allFields.filter(field => field.isContentField);
+    }
+    get doc() {
+        return this.mainField.renderedDoc;
+    }
+    get title() {
+        return this.mainField.getTitle();
+    }
+
+    cleanup = () => {
+        //dispose each subfields disposers, etc.
+    };
+
+    cloneBase = async (): Promise<Template> => {
+        const clone: Template = new Template(TemplateLayouts.BasicSettings);
+        clone.mainField = (await this.mainField.makeClone(undefined)) as unknown as DynamicField;
+        // clone.mainField.renderedDoc._width = this.mainField.renderedDoc._width;
+        // clone.mainField.renderedDoc._height = this.mainField.renderedDoc._height;
+        return clone;
+    };
+
+    printFieldInfo = () => {
+        this.allFields.forEach(field => {
+            const doc = field.renderedDoc;
+            console.log('title: ', field.getTitle(), ' width: ', doc?.width);
+        });
+    };
+
+    getRenderedDoc = () => {
+        return this.doc;
+    };
+
+    getFieldByID = (id: number): TemplateField => {
+        return this.allFields.filter(field => field.getID === id)[0];
+    };
+
+    getFieldByTitle = (title: string) => {
+        return this.allFields.filter(field => field.getTitle() === title)[0];
+    };
+
+    setupMainField = (templateInfo: FieldSettings) => {
+        return DynamicField.Create(templateInfo, 1);
+    };
+
+    get descriptionSummary(): string {
+        let summary: string = '';
+        this.contentFields.forEach(field => {
+            summary += `--- Field #${field.getID} (title: ${field.getTitle()}): ${field.getDescription ?? ''} ---`;
+        });
+        return summary;
+    }
+
+    get compiledContent(): string {
+        let summary: string = '';
+        this.contentFields.forEach(field => {
+            summary += `--- Field #${field.getID} (title: ${field.getTitle()}): ${field.getContent() ?? ''} ---`;
+        });
+        return summary;
+    }
+
+    isValidTemplate = (cols: Col[]) => {
+        const maxMatches = this.maxMatches(this.getMatches(cols));
+        return maxMatches === this.contentFields.length;
+    };
+
+    getMatches = (cols: Col[]): number[][] => {
+        const numFields = this.contentFields.length;
+
+        if (cols.length !== numFields) return [];
+
+        const matches: number[][] = Array(numFields)
+            .fill([])
+            .map(() => []);
+
+        this.contentFields.forEach((field, i) => {
+            matches[i] = field.matches(cols);
+        });
+
+        return matches;
+    };
+
+    maxMatches = (matches: number[][]) => {
+        if (matches.length === 0) return 0;
+
+        const fieldsCt = this.contentFields.length;
+        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;
+    };
+}
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
deleted file mode 100644
index 3c610b36a..000000000
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
+++ /dev/null
@@ -1,139 +0,0 @@
-import { makeAutoObservable } from 'mobx';
-import { Col } from './DocCreatorMenu';
-import { DynamicField } from './FieldTypes/DynamicField';
-import { Field, FieldSettings } from './FieldTypes/Field';
-import { TemplateLayouts } from './TemplateBackend';
-
-export class Template {
-    mainField: DynamicField;
-    private settings: FieldSettings;
-
-    constructor(templateInfo: FieldSettings) {
-        makeAutoObservable(this);
-        this.settings = templateInfo;
-        this.mainField = this.setupMainField(templateInfo);
-    }
-
-    get childFields(): Field[] {
-        return this.mainField.getSubfields;
-    }
-    get allFields(): Field[] {
-        return this.mainField.getAllSubfields;
-    }
-    get contentFields(): Field[] {
-        return this.allFields.filter(field => field.isContentField);
-    }
-    get doc() {
-        return this.mainField.renderedDoc;
-    }
-    get title() {
-        return this.mainField.getTitle();
-    }
-
-    cleanup = () => {
-        //dispose each subfields disposers, etc.
-    };
-
-    cloneBase = async (): Promise<Template> => {
-        const clone: Template = new Template(TemplateLayouts.BasicSettings);
-        clone.mainField = (await this.mainField.makeClone(undefined)) as unknown as DynamicField;
-        clone.mainField.renderedDoc._width = this.mainField.renderedDoc._width;
-        clone.mainField.renderedDoc._height = this.mainField.renderedDoc._height;
-        return clone;
-    };
-
-    printFieldInfo = () => {
-        this.allFields.forEach(field => {
-            const doc = field.renderedDoc;
-            console.log('title: ', field.getTitle(), ' width: ', doc.width);
-        });
-    };
-
-    getRenderedDoc = () => {
-        return this.doc;
-    };
-
-    getFieldByID = (id: number): Field => {
-        return this.allFields.filter(field => field.getID === id)[0];
-    };
-
-    getFieldByTitle = (title: string) => {
-        return this.allFields.filter(field => field.getTitle() === title)[0];
-    };
-
-    setupMainField = (templateInfo: FieldSettings) => {
-        return new DynamicField().init(templateInfo, 1);
-    };
-
-    get descriptionSummary(): string {
-        let summary: string = '';
-        this.contentFields.forEach(field => {
-            summary += `--- Field #${field.getID} (title: ${field.getTitle()}): ${field.getDescription ?? ''} ---`;
-        });
-        return summary;
-    }
-
-    get compiledContent(): string {
-        let summary: string = '';
-        this.contentFields.forEach(field => {
-            summary += `--- Field #${field.getID} (title: ${field.getTitle()}): ${field.getContent() ?? ''} ---`;
-        });
-        return summary;
-    }
-
-    isValidTemplate = (cols: Col[]) => {
-        const matches: number[][] = this.getMatches(cols);
-        const maxMatches: number = this.maxMatches(matches);
-        return maxMatches === this.contentFields.length;
-    };
-
-    getMatches = (cols: Col[]): number[][] => {
-        const numFields = this.contentFields.length;
-
-        if (cols.length !== numFields) return [];
-
-        const matches: number[][] = Array(numFields)
-            .fill([])
-            .map(() => []);
-
-        this.contentFields.forEach((field, i) => {
-            matches[i] = field.matches(cols);
-        });
-
-        return matches;
-    };
-
-    maxMatches = (matches: number[][]) => {
-        if (matches.length === 0) return 0;
-
-        const fieldsCt = this.contentFields.length;
-        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;
-    };
-}
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.ts b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.ts
new file mode 100644
index 000000000..9b0fac3a6
--- /dev/null
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.ts
@@ -0,0 +1,768 @@
+import { FieldSettings, ViewType } from './TemplateFieldTypes/TemplateField';
+
+export enum TemplateFieldType {
+    TEXT = 'text',
+    VISUAL = 'visual',
+    UNSET = 'unset',
+}
+
+export enum TemplateFieldSize {
+    TINY = 'tiny',
+    SMALL = 'small',
+    MEDIUM = 'medium',
+    LARGE = 'large',
+    HUGE = 'huge',
+}
+
+export class TemplateLayouts {
+    public static get allTemplates(): FieldSettings[] {
+        return Object.values(TemplateLayouts);
+    }
+
+    public static BasicSettings: FieldSettings = {
+        title: 'template_framework',
+        tl: [0, 0],
+        br: [400, 700],
+        viewType: ViewType.FREEFORM,
+        opts: {},
+    };
+
+    public static FourField001: FieldSettings = {
+        title: 'fourfield001',
+        tl: [0, 0],
+        br: [416, 700],
+        viewType: ViewType.FREEFORM,
+        opts: {
+            backgroundColor: '#C0B887',
+            _layout_borderRounding: '.05',
+            //borderColor: '#6B461F',
+            //borderWidth: '12',
+        },
+        subfields: [
+            {
+                viewType: ViewType.STATIC,
+                tl: [-0.95, -1],
+                br: [0.95, -0.85],
+                types: [TemplateFieldType.TEXT],
+                sizes: [TemplateFieldSize.TINY],
+                description: 'A title field for very short text that contextualizes the content.',
+                opts: {
+                    backgroundColor: 'transparent',
+                    text_fontColor: '#F1F0E9',
+                    hCentering: 'h-center',
+                    contentBold: true,
+                },
+            },
+            {
+                viewType: ViewType.STATIC,
+                tl: [-0.87, -0.83],
+                br: [0.87, 0.2],
+                types: [TemplateFieldType.TEXT, TemplateFieldType.VISUAL],
+                sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
+                description: 'The main focus of the template; could be an image, long text, etc.',
+                opts: {
+                    _layout_borderRounding: '.05',
+                    borderColor: '#8F5B25',
+                    borderWidth: 6,
+                    backgroundColor: '#CECAB9',
+                },
+            },
+            {
+                viewType: ViewType.STATIC,
+                tl: [-0.8, 0.2],
+                br: [0.8, 0.3],
+                types: [TemplateFieldType.TEXT],
+                sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL],
+                description: 'A caption for field #2, very short text.',
+                opts: {
+                    backgroundColor: 'transparent',
+                    hCentering: 'h-center',
+                    text_fontColor: '#F1F0E9',
+                },
+            },
+            {
+                viewType: ViewType.STATIC,
+                tl: [-0.87, 0.37],
+                br: [0.87, 0.96],
+                types: [TemplateFieldType.TEXT, TemplateFieldType.VISUAL],
+                sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
+                description: 'A medium-sized field for medium/long text.',
+                opts: {
+                    _layout_borderRounding: '.05',
+                    borderColor: '#8F5B25',
+                    borderWidth: 6,
+                    backgroundColor: '#CECAB9',
+                },
+            },
+        ],
+    };
+
+    public static FourField002: FieldSettings = {
+        title: 'fourfield002',
+        viewType: ViewType.FREEFORM,
+        tl: [0, 0],
+        br: [425, 778],
+        opts: {
+            backgroundColor: '#242425',
+        },
+        subfields: [
+            {
+                viewType: ViewType.STATIC,
+                tl: [-0.83, -0.95],
+                br: [0.83, -0.2],
+                types: [TemplateFieldType.VISUAL, TemplateFieldType.TEXT],
+                sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE],
+                description: 'A medium to large-sized field suitable for an image or longer text that should be the main focus.',
+                opts: {
+                    borderWidth: 8,
+                    borderColor: '#F8E71C',
+                    backgroundColor: '#242425',
+                    text_fontColor: 'white',
+                },
+            },
+            {
+                viewType: ViewType.STATIC,
+                tl: [-0.65, -0.2],
+                br: [0.65, -0.02],
+                types: [TemplateFieldType.TEXT],
+                sizes: [TemplateFieldSize.TINY],
+                description: 'A tiny field for just a word or two of plain text.',
+                opts: {
+                    backgroundColor: 'transparent',
+                    text_fontColor: 'white',
+                    hCentering: 'h-center',
+                    text_transform: 'uppercase',
+                },
+            },
+            {
+                viewType: ViewType.STATIC,
+                tl: [-0.65, 0],
+                br: [0.65, 0.18],
+                types: [TemplateFieldType.TEXT],
+                sizes: [TemplateFieldSize.TINY],
+                description: 'A tiny field for just a word or two of plain text.',
+                opts: {
+                    backgroundColor: 'transparent',
+                    text_fontColor: 'white',
+                    hCentering: 'h-center',
+                    text_transform: 'uppercase',
+                },
+            },
+            {
+                viewType: ViewType.STATIC,
+                tl: [-0.83, 0.2],
+                br: [0.83, 0.95],
+                types: [TemplateFieldType.TEXT],
+                sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
+                description: 'A medium to large-sized field suitable for longer text that should contextualize field 1.',
+                opts: {
+                    borderWidth: 8,
+                    borderColor: '#F8E71C',
+                    text_fontColor: 'white',
+                    backgroundColor: '#242425',
+                },
+            },
+            {
+                viewType: ViewType.DEC,
+                tl: [-0.8, -0.075],
+                br: [-0.525, 0.075],
+                opts: {
+                    backgroundColor: '#F8E71C',
+                    _rotation: 45,
+                },
+            },
+            {
+                viewType: ViewType.DEC,
+                tl: [-0.3075, -0.0245],
+                br: [-0.2175, 0.0245],
+                opts: {
+                    backgroundColor: '#F8E71C',
+                    _rotation: 45,
+                },
+            },
+            {
+                viewType: ViewType.DEC,
+                tl: [-0.045, -0.0245],
+                br: [0.045, 0.0245],
+                opts: {
+                    backgroundColor: '#F8E71C',
+                    _rotation: 45,
+                },
+            },
+            {
+                viewType: ViewType.DEC,
+                tl: [0.2175, -0.0245],
+                br: [0.3075, 0.0245],
+                opts: {
+                    backgroundColor: '#F8E71C',
+                    _rotation: 45,
+                },
+            },
+            {
+                viewType: ViewType.DEC,
+                tl: [0.525, -0.075],
+                br: [0.8, 0.075],
+                opts: {
+                    backgroundColor: '#F8E71C',
+                    _rotation: 45,
+                },
+            },
+        ],
+    };
+
+    // public static FourField003: TemplateDocInfos = {
+    //     title: 'fourfield3',
+    //     width: 477,
+    //     height: 662,
+    //     opts: {
+    //         backgroundColor: '#9E9C95'
+    //     },
+    //     fields: [{
+    //         tl: [-.875, -.9],
+    //         br: [.875, .7],
+    //         types: [TemplateFieldType.VISUAL],
+    //         sizes: [TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
+    //         description: '',
+    //         opts: {
+    //             borderWidth: '15',
+    //             borderColor: '#E0E0DA',
+    //         }
+    //     }, {
+    //         tl: [-.95, .8],
+    //         br: [-.1, .95],
+    //         types: [TemplateFieldType.TEXT],
+    //         sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL],
+    //         description: '',
+    //         opts: {
+    //             backgroundColor: 'transparent',
+    //             color: 'white',
+    //             contentXCentering: 'h-right',
+    //         }
+    //     }, {
+    //         tl: [.1, .8],
+    //         br: [.95, .95],
+    //         types: [TemplateFieldType.TEXT],
+    //         sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL],
+    //         description: '',
+    //         opts: {
+    //             backgroundColor: 'transparent',
+    //             color: 'red',
+    //             fontTransform: 'uppercase',
+    //             contentXCentering: 'h-left'
+    //         }
+    //     }, {
+    //         tl: [0, -.9],
+    //         br: [.85, -.66],
+    //         types: [TemplateFieldType.TEXT, TemplateFieldType.VISUAL],
+    //         sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
+    //         description: '',
+    //         opts: {
+    //             backgroundColor: 'transparent',
+    //             contentXCentering: 'h-right'
+    //         }
+    //     }],
+    //     decorations: [{
+    //         tl: [-.025, .8],
+    //         br: [.025, .95],
+    //         opts: {
+    //             backgroundColor: '#E0E0DA',
+    //         }
+    //     }]
+    // };
+
+    public static FourField004: FieldSettings = {
+        title: 'fourfield04',
+        viewType: ViewType.FREEFORM,
+        tl: [0, 0],
+        br: [414, 583],
+        opts: {
+            backgroundColor: '#6CCAF0',
+            //borderColor: '#1088C3',
+            //borderWidth: '10',
+        },
+        subfields: [
+            {
+                viewType: ViewType.STATIC,
+                tl: [-0.86, -0.92],
+                br: [-0.075, -0.77],
+                types: [TemplateFieldType.TEXT],
+                sizes: [TemplateFieldSize.TINY],
+                description: 'A tiny field for just a word or two of plain text.',
+                opts: {
+                    backgroundColor: '#E2B4F5',
+                    borderWidth: 9,
+                    borderColor: '#9222F1',
+                    hCentering: 'h-center',
+                },
+            },
+            {
+                viewType: ViewType.STATIC,
+                tl: [0.075, -0.92],
+                br: [0.86, -0.77],
+                types: [TemplateFieldType.TEXT],
+                sizes: [TemplateFieldSize.TINY],
+                description: 'A tiny field for just a word or two of plain text.',
+                opts: {
+                    backgroundColor: '#F5B4DD',
+                    borderWidth: 9,
+                    borderColor: '#E260F3',
+                    hCentering: 'h-center',
+                },
+            },
+            {
+                viewType: ViewType.STATIC,
+                tl: [-0.81, -0.64],
+                br: [0.81, 0.48],
+                types: [TemplateFieldType.VISUAL],
+                sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
+                description: 'A large to huge field for visual content that is the main content of the template.',
+                opts: {
+                    borderWidth: 16,
+                    borderColor: '#A2BD77',
+                },
+            },
+            {
+                viewType: ViewType.STATIC,
+                tl: [-0.86, 0.6],
+                br: [0.86, 0.92],
+                types: [TemplateFieldType.TEXT],
+                sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE],
+                description: 'A medium to large field for text that describes the visual content above',
+                opts: {
+                    borderWidth: 9,
+                    borderColor: '#F0D601',
+                    backgroundColor: '#F3F57D',
+                },
+            },
+            {
+                viewType: ViewType.DEC,
+                tl: [-0.852, -0.67],
+                br: [0.852, 0.51],
+                opts: {
+                    backgroundColor: 'transparent',
+                    borderColor: '#007C0C',
+                    borderWidth: 10,
+                },
+            },
+        ],
+    };
+
+    public static FourField005: FieldSettings = {
+        title: 'fourfield05',
+        viewType: ViewType.FREEFORM,
+        tl: [0, 0],
+        br: [400, 550],
+        opts: {
+            backgroundColor: '#95A575',
+        },
+        subfields: [
+            {
+                viewType: ViewType.STATIC,
+                tl: [-0.9, -0.925],
+                br: [-0.075, -0.775],
+                types: [TemplateFieldType.TEXT],
+                sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL],
+                description: 'A small text field for a title or word(s) that categorize the rest of the content.',
+                opts: {
+                    borderColor: '#3B4A2C',
+                    borderWidth: 8,
+                    hCentering: 'h-center',
+                    backgroundColor: '#B8DC90',
+                },
+            },
+            {
+                viewType: ViewType.STATIC,
+                tl: [0.075, -0.925],
+                br: [0.9, -0.775],
+                types: [TemplateFieldType.TEXT],
+                sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL],
+                description: 'A small text field for a title that categorizes the rest of the content.',
+                opts: {
+                    borderColor: '#3B4A2C',
+                    borderWidth: 8,
+                    hCentering: 'h-center',
+                    backgroundColor: '#B8DC90',
+                },
+            },
+            {
+                viewType: ViewType.DEC,
+                tl: [-0.82, -0.4],
+                br: [-0.5, -0.2],
+                opts: {
+                    backgroundColor: '#94B058',
+                    borderColor: '#3B4A2C',
+                    borderWidth: 8,
+                },
+            },
+            {
+                viewType: ViewType.STATIC,
+                tl: [-0.66, -0.65],
+                br: [0.66, 0.25],
+                types: [TemplateFieldType.VISUAL],
+                sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE],
+                description: 'A medium to large field in the center of the template, for the main visual content.',
+                opts: {
+                    borderColor: '#3B4A2C',
+                    borderWidth: 8,
+                    backgroundColor: '#B8DC90',
+                },
+            },
+            {
+                viewType: ViewType.STATIC,
+                tl: [-0.875, 0.425],
+                br: [0.875, 0.925],
+                types: [TemplateFieldType.TEXT],
+                sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE],
+                description: 'A medium to large field at the bottom of the template, for the main text content.',
+                opts: {
+                    borderColor: '#3B4A2C',
+                    borderWidth: 8,
+                    hCentering: 'h-center',
+                    backgroundColor: '#B8DC90',
+                },
+            },
+            {
+                viewType: ViewType.DEC,
+                tl: [-1.1, -0.62],
+                br: [-0.9, -0.5],
+                opts: {
+                    backgroundColor: '#7A9D31',
+                    borderColor: '#3B4A2C',
+                    borderWidth: 8,
+                },
+            },
+            {
+                viewType: ViewType.DEC,
+                tl: [-1.1, 0],
+                br: [-0.9, 0.15],
+                opts: {
+                    backgroundColor: '#94B058',
+                    borderColor: '#3B4A2C',
+                    borderWidth: 8,
+                },
+            },
+            {
+                viewType: ViewType.DEC,
+                tl: [-0.93, -0.265],
+                br: [-0.715, -0.125],
+                opts: {
+                    backgroundColor: '#728745',
+                    borderColor: '#3B4A2C',
+                    borderWidth: 8,
+                },
+            },
+            {
+                viewType: ViewType.DEC,
+                tl: [0.7, -0.45],
+                br: [0.85, -0.3],
+                opts: {
+                    backgroundColor: '#7A9D31',
+                    borderColor: '#3B4A2C',
+                    borderWidth: 8,
+                },
+            },
+            {
+                viewType: ViewType.DEC,
+                tl: [0.8, 0.03],
+                br: [1.2, 0.33],
+                opts: {
+                    backgroundColor: '#728745',
+                    borderColor: '#3B4A2C',
+                    borderWidth: 8,
+                },
+            },
+            {
+                viewType: ViewType.DEC,
+                tl: [0.875, -0.13],
+                br: [1.2, 0.12],
+                opts: {
+                    backgroundColor: '#94B058',
+                    borderColor: '#3B4A2C',
+                    borderWidth: 8,
+                },
+            },
+        ],
+    };
+
+    public static FourFieldCarousel: FieldSettings = {
+        title: 'title_fourfieldcarousel',
+        viewType: ViewType.FREEFORM,
+        tl: [0, 0],
+        br: [500, 600],
+        opts: {
+            backgroundColor: '#D7CBAB',
+        },
+        subfields: [
+            {
+                viewType: ViewType.STATIC,
+                tl: [-0.8, -0.9],
+                br: [0.8, -0.5],
+                types: [TemplateFieldType.TEXT],
+                sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL],
+                description: 'A small text field for a title that categorizes the rest of the content.',
+                opts: {
+                    hCentering: 'h-center',
+                    backgroundColor: 'transparent',
+                    text_transform: 'uppercase',
+                },
+            },
+            {
+                viewType: ViewType.CAROUSEL3D,
+                tl: [-0.9, -0.5],
+                br: [0.9, 0.25],
+                opts: {
+                    borderColor: '#847F69',
+                    borderWidth: 8,
+                    backgroundColor: '#C8BA94',
+                },
+                subfields: [
+                    {
+                        viewType: ViewType.STATIC,
+                        tl: [-0.4, -0.6],
+                        br: [0.4, 0.6],
+                        types: [TemplateFieldType.VISUAL, TemplateFieldType.TEXT],
+                        sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
+                        description: 'A medium to large field for content that will share central focus with other content in the carousel.',
+                        opts: {
+                            //borderColor: 'yellow',
+                            //borderWidth: '8',
+                        },
+                    },
+                    {
+                        viewType: ViewType.STATIC,
+                        tl: [-0.4, -0.6],
+                        br: [0.4, 0.6],
+                        types: [TemplateFieldType.VISUAL, TemplateFieldType.TEXT],
+                        sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
+                        description: 'A medium to large field for content that will share central focus with other content in the carousel.',
+                        opts: {
+                            //borderColor: 'black',
+                            //borderWidth: '8',
+                        },
+                    },
+                    {
+                        viewType: ViewType.STATIC,
+                        tl: [-0.4, -0.6],
+                        br: [0.4, 0.6],
+                        types: [TemplateFieldType.VISUAL, TemplateFieldType.TEXT],
+                        sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
+                        description: 'A medium to large field for content that will share central focus with other content in the carousel.',
+                        opts: {
+                            //borderColor: 'yellow',
+                            //borderWidth: '8',
+                        },
+                    },
+                ],
+            },
+            {
+                viewType: ViewType.STATIC,
+                tl: [-0.9, 0.35],
+                br: [0.9, 0.9],
+                types: [TemplateFieldType.TEXT],
+                sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE],
+                description: 'A medium text field for a description of the content in the carousel.',
+                opts: {
+                    hCentering: 'h-center',
+                    backgroundColor: 'transparent',
+                },
+            },
+        ],
+    };
+
+    public static ThreeField001: FieldSettings = {
+        title: 'threefield001',
+        viewType: ViewType.FREEFORM,
+        tl: [0, 0],
+        br: [575, 770],
+        opts: {
+            backgroundColor: '#DDD3A9',
+        },
+        subfields: [
+            {
+                viewType: ViewType.FREEFORM,
+                tl: [-0.66, -0.747],
+                br: [0.66, 0.247],
+                description: 'A medium to large field for visual content that is the central focus.',
+                opts: {
+                    borderColor: 'yellow',
+                    borderWidth: 8,
+                    backgroundColor: '#DDD3A9',
+                    _rotation: 45,
+                },
+                subfields: [
+                    {
+                        viewType: ViewType.STATIC,
+                        tl: [-1.25, -1.25],
+                        br: [1.25, 1.25],
+                        types: [TemplateFieldType.VISUAL],
+                        sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
+                        description: 'A medium to large field for visual content that is the central focus.',
+                        opts: {
+                            _rotation: -45,
+                        },
+                    },
+                ],
+            },
+            {
+                viewType: ViewType.STATIC,
+                tl: [-0.7, 0.2],
+                br: [0.7, 0.46],
+                types: [TemplateFieldType.TEXT],
+                sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL],
+                description: 'A very small text field for one to a few words. A good caption for the image.',
+                opts: {
+                    backgroundColor: 'transparent',
+                    hCentering: 'h-center',
+                },
+            },
+            {
+                viewType: ViewType.STATIC,
+                tl: [-0.95, 0.5],
+                br: [0.95, 0.95],
+                types: [TemplateFieldType.TEXT],
+                sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE],
+                description: 'A medium to large text field for a thorough description of the image. ',
+                opts: {
+                    backgroundColor: 'transparent',
+                    text_fontColor: 'white',
+                },
+            },
+            {
+                viewType: ViewType.FREEFORM,
+                tl: [0.2, -1.32],
+                br: [1.8, -0.66],
+                opts: {
+                    backgroundColor: '#CEB155',
+                    _rotation: 45,
+                },
+                subfields: [
+                    {
+                        viewType: ViewType.DEC,
+                        tl: [-1, -0.7],
+                        br: [1, -0.625],
+                        opts: {
+                            backgroundColor: 'yellow',
+                        },
+                    },
+                ],
+            },
+            {
+                viewType: ViewType.FREEFORM,
+                tl: [-1.8, -1.32],
+                br: [-0.2, -0.66],
+                opts: {
+                    backgroundColor: '#CEB155',
+                    _rotation: 135,
+                },
+                subfields: [
+                    {
+                        viewType: ViewType.DEC,
+                        tl: [-1, -0.7],
+                        br: [1, -0.625],
+                        opts: {
+                            backgroundColor: 'yellow',
+                        },
+                    },
+                ],
+            },
+            {
+                viewType: ViewType.FREEFORM,
+                tl: [0.33, 0.75],
+                br: [1.66, 1.25],
+                opts: {
+                    backgroundColor: '#CEB155',
+                    _rotation: 135,
+                },
+                subfields: [
+                    {
+                        viewType: ViewType.DEC,
+                        tl: [-1, -0.7],
+                        br: [1, -0.625],
+                        opts: {
+                            backgroundColor: 'yellow',
+                        },
+                    },
+                ],
+            },
+            {
+                viewType: ViewType.FREEFORM,
+                tl: [-1.66, 0.75],
+                br: [-0.33, 1.25],
+                opts: {
+                    backgroundColor: '#CEB155',
+                    _rotation: 45,
+                },
+                subfields: [
+                    {
+                        viewType: ViewType.DEC,
+                        tl: [-1, -0.7],
+                        br: [1, -0.625],
+                        opts: {
+                            backgroundColor: 'yellow',
+                        },
+                    },
+                ],
+            },
+        ],
+    };
+
+    public static ThreeField002: FieldSettings = {
+        title: 'threefield002',
+        viewType: ViewType.FREEFORM,
+        tl: [0, 0],
+        br: [477, 662],
+        opts: {
+            backgroundColor: '#9E9C95',
+        },
+        subfields: [
+            {
+                viewType: ViewType.STATIC,
+                tl: [-0.875, -0.9],
+                br: [0.875, 0.7],
+                types: [TemplateFieldType.VISUAL],
+                sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
+                description: 'A medium to large visual field for the main content of the template',
+                opts: {
+                    borderWidth: 15,
+                    borderColor: '#E0E0DA',
+                },
+            },
+            {
+                viewType: ViewType.STATIC,
+                tl: [0.1, 0.775],
+                br: [0.95, 0.975],
+                types: [TemplateFieldType.TEXT],
+                sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL],
+                description: 'A very small text field for one to a few words. The content should represent a general categorization of the image.',
+                opts: {
+                    backgroundColor: 'transparent',
+                    text_fontColor: '#AF0D0D',
+                    text_transform: 'uppercase',
+                    contentBold: true,
+                    hCentering: 'h-left',
+                },
+            },
+            {
+                viewType: ViewType.STATIC,
+                tl: [-0.95, 0.775],
+                br: [-0.1, 0.975],
+                types: [TemplateFieldType.TEXT],
+                sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL],
+                description: 'A very small text field for one to a few words. The content should contextualize field 2.',
+                opts: {
+                    backgroundColor: 'transparent',
+                    text_fontColor: 'black',
+                    hCentering: 'h-right',
+                },
+            },
+            {
+                viewType: ViewType.DEC,
+                tl: [-0.025, 0.8],
+                br: [0.025, 0.95],
+                opts: {
+                    backgroundColor: '#E0E0DA',
+                },
+            },
+        ],
+    };
+}
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
deleted file mode 100644
index 2b32d49aa..000000000
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
+++ /dev/null
@@ -1,771 +0,0 @@
-import { FieldSettings, ViewType } from "./FieldTypes/Field";
-
-export enum TemplateFieldType {
-    TEXT = 'text',
-    VISUAL = 'visual',
-    UNSET = 'unset',
-}
-
-export enum TemplateFieldSize {
-    TINY = 'tiny',
-    SMALL = 'small',
-    MEDIUM = 'medium',
-    LARGE = 'large',
-    HUGE = 'huge',
-}
-
-export class TemplateLayouts {
-    public static get allTemplates(): FieldSettings[] {
-        return Object.values(TemplateLayouts);
-    }
-
-    public static BasicSettings: FieldSettings = {
-        title: 'template_framework',
-        tl: [0, 0],
-        br: [400, 700],
-        viewType: ViewType.FREEFORM,
-        opts: {}
-    }
-
-    public static FourField001: FieldSettings = {
-        title: 'fourfield001',
-        tl: [0, 0],
-        br: [416, 700],
-        viewType: ViewType.FREEFORM,
-        opts: {
-            backgroundColor: '#C0B887',
-            _layout_borderRounding: '.05',
-            //borderColor: '#6B461F',
-            //borderWidth: '12',
-        },
-        subfields: [
-            {
-                viewType: ViewType.STATIC,
-                tl: [-0.95, -1],
-                br: [0.95, -0.85],
-                types: [TemplateFieldType.TEXT],
-                sizes: [TemplateFieldSize.TINY],
-                description: 'A title field for very short text that contextualizes the content.',
-                opts: {
-                    backgroundColor: 'transparent',
-                    text_fontColor: '#F1F0E9',
-                    hCentering: 'h-center',
-                    contentBold: true,
-                },
-            },
-            {
-                viewType: ViewType.STATIC,
-                tl: [-0.87, -0.83],
-                br: [0.87, 0.2],
-                types: [TemplateFieldType.TEXT, TemplateFieldType.VISUAL],
-                sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
-                description: 'The main focus of the template; could be an image, long text, etc.',
-                opts: {
-                    _layout_borderRounding: '.05',
-                    borderColor: '#8F5B25',
-                    borderWidth: 6,
-                    backgroundColor: '#CECAB9',
-                },
-            },
-            {
-                viewType: ViewType.STATIC,
-                tl: [-0.8, 0.2],
-                br: [0.8, 0.3],
-                types: [TemplateFieldType.TEXT],
-                sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL],
-                description: 'A caption for field #2, very short text.',
-                opts: {
-                    backgroundColor: 'transparent',
-                    hCentering: 'h-center',
-                    text_fontColor: '#F1F0E9',
-                },
-            },
-            {
-                viewType: ViewType.STATIC,
-                tl: [-0.87, 0.37],
-                br: [0.87, 0.96],
-                types: [TemplateFieldType.TEXT, TemplateFieldType.VISUAL],
-                sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
-                description: 'A medium-sized field for medium/long text.',
-                opts: {
-                    _layout_borderRounding: '.05',
-                    borderColor: '#8F5B25',
-                    borderWidth: 6,
-                    backgroundColor: '#CECAB9',
-                },
-            },
-        ],
-    };
-
-    public static FourField002: FieldSettings = {
-        title: 'fourfield002',
-        viewType: ViewType.FREEFORM,
-        tl: [0,0],
-        br: [425, 778],
-        opts: {
-            backgroundColor: '#242425',
-        },
-        subfields: [
-            {
-                viewType: ViewType.STATIC,
-                tl: [-0.83, -0.95],
-                br: [0.83, -0.2],
-                types: [TemplateFieldType.VISUAL, TemplateFieldType.TEXT],
-                sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE],
-                description: 'A medium to large-sized field suitable for an image or longer text that should be the main focus.',
-                opts: {
-                    borderWidth: 8,
-                    borderColor: '#F8E71C',
-                    backgroundColor: '#242425',
-                    text_fontColor: 'white',
-                },
-            },
-            {
-                viewType: ViewType.STATIC,
-                tl: [-0.65, -0.2],
-                br: [0.65, -0.02],
-                types: [TemplateFieldType.TEXT],
-                sizes: [TemplateFieldSize.TINY],
-                description: 'A tiny field for just a word or two of plain text.',
-                opts: {
-                    backgroundColor: 'transparent',
-                    text_fontColor: 'white',
-                    hCentering: 'h-center',
-                    text_transform: 'uppercase',
-                },
-            },
-            {
-                viewType: ViewType.STATIC,
-                tl: [-0.65, 0],
-                br: [0.65, 0.18],
-                types: [TemplateFieldType.TEXT],
-                sizes: [TemplateFieldSize.TINY],
-                description: 'A tiny field for just a word or two of plain text.',
-                opts: {
-                    backgroundColor: 'transparent',
-                    text_fontColor: 'white',
-                    hCentering: 'h-center',
-                    text_transform: 'uppercase',
-                },
-            },
-            {
-                viewType: ViewType.STATIC,
-                tl: [-0.83, 0.2],
-                br: [0.83, 0.95],
-                types: [TemplateFieldType.TEXT],
-                sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
-                description: 'A medium to large-sized field suitable for longer text that should contextualize field 1.',
-                opts: {
-                    borderWidth: 8,
-                    borderColor: '#F8E71C',
-                    text_fontColor: 'white',
-                    backgroundColor: '#242425',
-                },
-            },
-            {
-                viewType: ViewType.DEC,
-                tl: [-0.8, -0.075],
-                br: [-0.525, 0.075],
-                opts: {
-                    backgroundColor: '#F8E71C',
-                    _rotation: 45,
-                },
-            },
-            {
-                viewType: ViewType.DEC,
-                tl: [-0.3075, -0.0245],
-                br: [-0.2175, 0.0245],
-                opts: {
-                    backgroundColor: '#F8E71C',
-                    _rotation: 45,
-                },
-            },
-            {
-                viewType: ViewType.DEC,
-                tl: [-0.045, -0.0245],
-                br: [0.045, 0.0245],
-                opts: {
-                    backgroundColor: '#F8E71C',
-                    _rotation: 45,
-                },
-            },
-            {
-                viewType: ViewType.DEC,
-                tl: [0.2175, -0.0245],
-                br: [0.3075, 0.0245],
-                opts: {
-                    backgroundColor: '#F8E71C',
-                    _rotation: 45,
-                },
-            },
-            {
-                viewType: ViewType.DEC,
-                tl: [0.525, -0.075],
-                br: [0.8, 0.075],
-                opts: {
-                    backgroundColor: '#F8E71C',
-                    _rotation: 45,
-                },
-            },
-        ],
-    };
-
-    // public static FourField003: TemplateDocInfos = {
-    //     title: 'fourfield3',
-    //     width: 477,
-    //     height: 662,
-    //     opts: {
-    //         backgroundColor: '#9E9C95'
-    //     },
-    //     fields: [{
-    //         tl: [-.875, -.9],
-    //         br: [.875, .7],
-    //         types: [TemplateFieldType.VISUAL],
-    //         sizes: [TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
-    //         description: '',
-    //         opts: {
-    //             borderWidth: '15',
-    //             borderColor: '#E0E0DA',
-    //         }
-    //     }, {
-    //         tl: [-.95, .8],
-    //         br: [-.1, .95],
-    //         types: [TemplateFieldType.TEXT],
-    //         sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL],
-    //         description: '',
-    //         opts: {
-    //             backgroundColor: 'transparent',
-    //             color: 'white',
-    //             contentXCentering: 'h-right',
-    //         }
-    //     }, {
-    //         tl: [.1, .8],
-    //         br: [.95, .95],
-    //         types: [TemplateFieldType.TEXT],
-    //         sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL],
-    //         description: '',
-    //         opts: {
-    //             backgroundColor: 'transparent',
-    //             color: 'red',
-    //             fontTransform: 'uppercase',
-    //             contentXCentering: 'h-left'
-    //         }
-    //     }, {
-    //         tl: [0, -.9],
-    //         br: [.85, -.66],
-    //         types: [TemplateFieldType.TEXT, TemplateFieldType.VISUAL],
-    //         sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
-    //         description: '',
-    //         opts: {
-    //             backgroundColor: 'transparent',
-    //             contentXCentering: 'h-right'
-    //         }
-    //     }],
-    //     decorations: [{
-    //         tl: [-.025, .8],
-    //         br: [.025, .95],
-    //         opts: {
-    //             backgroundColor: '#E0E0DA',
-    //         }
-    //     }]
-    // };
-
-    public static FourField004: FieldSettings = {
-        title: 'fourfield04',
-        viewType: ViewType.FREEFORM,
-        tl: [0,0],
-        br: [414,583],
-        opts: {
-            backgroundColor: '#6CCAF0',
-            //borderColor: '#1088C3',
-            //borderWidth: '10',
-        },
-        subfields: [
-            {
-                viewType: ViewType.STATIC,
-                tl: [-0.86, -0.92],
-                br: [-0.075, -0.77],
-                types: [TemplateFieldType.TEXT],
-                sizes: [TemplateFieldSize.TINY],
-                description: 'A tiny field for just a word or two of plain text.',
-                opts: {
-                    backgroundColor: '#E2B4F5',
-                    borderWidth: 9,
-                    borderColor: '#9222F1',
-                    hCentering: 'h-center',
-                },
-            },
-            {
-                viewType: ViewType.STATIC,
-                tl: [0.075, -0.92],
-                br: [0.86, -0.77],
-                types: [TemplateFieldType.TEXT],
-                sizes: [TemplateFieldSize.TINY],
-                description: 'A tiny field for just a word or two of plain text.',
-                opts: {
-                    backgroundColor: '#F5B4DD',
-                    borderWidth: 9,
-                    borderColor: '#E260F3',
-                    hCentering: 'h-center',
-                },
-            },
-            {
-                viewType: ViewType.STATIC,
-                tl: [-0.81, -0.64],
-                br: [0.81, 0.48],
-                types: [TemplateFieldType.VISUAL],
-                sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
-                description: 'A large to huge field for visual content that is the main content of the template.',
-                opts: {
-                    borderWidth: 16,
-                    borderColor: '#A2BD77',
-                },
-            },
-            {
-                viewType: ViewType.STATIC,
-                tl: [-0.86, 0.6],
-                br: [0.86, 0.92],
-                types: [TemplateFieldType.TEXT],
-                sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE],
-                description: 'A medium to large field for text that describes the visual content above',
-                opts: {
-                    borderWidth: 9,
-                    borderColor: '#F0D601',
-                    backgroundColor: '#F3F57D',
-                },
-            },
-            {
-                viewType: ViewType.DEC,
-                tl: [-0.852, -0.67],
-                br: [0.852, 0.51],
-                opts: {
-                    backgroundColor: 'transparent',
-                    borderColor: '#007C0C',
-                    borderWidth: 10,
-                },
-            },
-        ],
-    };
-
-    public static FourField005: FieldSettings = {
-        title: 'fourfield05',
-        viewType: ViewType.FREEFORM,
-        tl: [0,0],
-        br: [400,550],
-        opts: {
-            backgroundColor: '#95A575',
-        },
-        subfields: [
-            {
-                viewType: ViewType.STATIC,
-                tl: [-0.9, -.925],
-                br: [-.075, -.775],
-                types: [TemplateFieldType.TEXT],
-                sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL],
-                description: 'A small text field for a title or word(s) that categorize the rest of the content.',
-                opts: {
-                    borderColor: '#3B4A2C',
-                    borderWidth: 8,
-                    hCentering: "h-center",
-                    backgroundColor: '#B8DC90',
-                },
-            },
-            {
-                viewType: ViewType.STATIC,
-                tl: [.075, -.925],
-                br: [.9, -.775],
-                types: [TemplateFieldType.TEXT],
-                sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL],
-                description: 'A small text field for a title that categorizes the rest of the content.',
-                opts: {
-                    borderColor: '#3B4A2C',
-                    borderWidth: 8,
-                    hCentering: "h-center",
-                    backgroundColor: '#B8DC90',
-                },
-            },
-            {
-                viewType: ViewType.DEC,
-                tl: [-.82, -.4],
-                br: [-.5, -.2],
-                opts: {
-                    backgroundColor: '#94B058',
-                    borderColor: '#3B4A2C',
-                    borderWidth: 8,
-                },
-            },
-            {
-                viewType: ViewType.STATIC,
-                tl: [-0.66, -.65],
-                br: [0.66, .25],
-                types: [TemplateFieldType.VISUAL],
-                sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE],
-                description: 'A medium to large field in the center of the template, for the main visual content.',
-                opts: {
-                    borderColor: '#3B4A2C',
-                    borderWidth: 8,
-                    backgroundColor: '#B8DC90',
-                },
-            },
-            {
-                viewType: ViewType.STATIC,
-                tl: [-.875, .425],
-                br: [0.875, .925],
-                types: [TemplateFieldType.TEXT],
-                sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE],
-                description: 'A medium to large field at the bottom of the template, for the main text content.',
-                opts: {
-                    borderColor: '#3B4A2C',
-                    borderWidth: 8,
-                    hCentering: "h-center",
-                    backgroundColor: '#B8DC90',
-                },
-            },
-            {
-                viewType: ViewType.DEC,
-                tl: [-1.1, -.62],
-                br: [-.9, -.5],
-                opts: {
-                    backgroundColor: '#7A9D31',
-                    borderColor: '#3B4A2C',
-                    borderWidth: 8,
-                },
-            },
-            {
-                viewType: ViewType.DEC,
-                tl: [-1.1, 0],
-                br: [-.9, .15],
-                opts: {
-                    backgroundColor: '#94B058',
-                    borderColor: '#3B4A2C',
-                    borderWidth: 8,
-                },
-            },
-            {
-                viewType: ViewType.DEC,
-                tl: [-.93, -.265],
-                br: [-.715, -.125],
-                opts: {
-                    backgroundColor: '#728745',
-                    borderColor: '#3B4A2C',
-                    borderWidth: 8,
-                },
-            },
-            {
-                viewType: ViewType.DEC,
-                tl: [.7, -.45],
-                br: [.85, -.3],
-                opts: {
-                    backgroundColor: '#7A9D31',
-                    borderColor: '#3B4A2C',
-                    borderWidth: 8,
-                },
-            },
-            {
-                viewType: ViewType.DEC,
-                tl: [.8, .03],
-                br: [1.2, .33],
-                opts: {
-                    backgroundColor: '#728745',
-                    borderColor: '#3B4A2C',
-                    borderWidth: 8,
-                },
-            },
-            {
-                viewType: ViewType.DEC,
-                tl: [.875, -.13],
-                br: [1.2, .12],
-                opts: {
-                    backgroundColor: '#94B058',
-                    borderColor: '#3B4A2C',
-                    borderWidth: 8,
-                },
-            },
-        ]
-    }
-
-    public static FourFieldCarousel: FieldSettings = {
-        title: 'title_fourfieldcarousel',
-        viewType: ViewType.FREEFORM,
-        tl:[0,0],
-        br:[500, 600],
-        opts: {
-            backgroundColor: '#D7CBAB',
-        },
-        subfields: [
-            {
-                viewType: ViewType.STATIC,
-                tl: [-0.8, -.9],
-                br: [0.8, -.5],
-                types: [TemplateFieldType.TEXT],
-                sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL],
-                description: 'A small text field for a title that categorizes the rest of the content.',
-                opts: {
-                    hCentering: "h-center",
-                    backgroundColor: 'transparent',
-                    text_transform: 'uppercase',
-                },
-            },
-            {
-                viewType: ViewType.CAROUSEL3D,
-                tl: [-0.9, -.5],
-                br: [0.9, .25],
-                opts: {
-                    borderColor: '#847F69',
-                    borderWidth: 8,
-                    backgroundColor: '#C8BA94',
-                },
-                subfields: [
-                    {
-                        viewType: ViewType.STATIC,
-                        tl: [-.4, -.6],
-                        br: [.4, .6],
-                        types: [TemplateFieldType.VISUAL, TemplateFieldType.TEXT],
-                        sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
-                        description: 'A medium to large field for content that will share central focus with other content in the carousel.',
-                        opts: {
-                            //borderColor: 'yellow',
-                            //borderWidth: '8',
-                        },
-                    },
-                    {
-                        viewType: ViewType.STATIC,
-                        tl: [-.4, -.6],
-                        br: [.4, .6],
-                        types: [TemplateFieldType.VISUAL, TemplateFieldType.TEXT],
-                        sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
-                        description: 'A medium to large field for content that will share central focus with other content in the carousel.',
-                        opts: {
-                            //borderColor: 'black',
-                            //borderWidth: '8',
-                        },
-                    },
-                    {
-                        viewType: ViewType.STATIC,
-                        tl: [-.4, -.6],
-                        br: [.4, .6],
-                        types: [TemplateFieldType.VISUAL, TemplateFieldType.TEXT],
-                        sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
-                        description: 'A medium to large field for content that will share central focus with other content in the carousel.',
-                        opts: {
-                            //borderColor: 'yellow',
-                            //borderWidth: '8',
-                        },
-                    },
-                ]
-            },
-            {
-                viewType: ViewType.STATIC,
-                tl: [-0.9, .35],
-                br: [0.9, .9],
-                types: [TemplateFieldType.TEXT],
-                sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE],
-                description: 'A medium text field for a description of the content in the carousel.',
-                opts: {
-                    hCentering: "h-center",
-                    backgroundColor: 'transparent',
-                },
-            },
-        ]
-    }
-
-
-    public static ThreeField001: FieldSettings = {
-        title: 'threefield001',
-        viewType: ViewType.FREEFORM,
-        tl: [0,0],
-        br: [575, 770],
-        opts: {
-            backgroundColor: '#DDD3A9',
-        },
-        subfields: [
-            {
-                viewType: ViewType.FREEFORM,
-                tl: [-0.66, -0.747],
-                br: [0.66, 0.247],
-                description: 'A medium to large field for visual content that is the central focus.',
-                opts: {
-                    borderColor: 'yellow',
-                    borderWidth: 8,
-                    backgroundColor: '#DDD3A9',
-                    _rotation: 45,
-                },
-                subfields: [
-                    {
-                    viewType: ViewType.STATIC,
-                    tl: [-1.25, -1.25],
-                    br: [1.25, 1.25],
-                    types: [TemplateFieldType.VISUAL],
-                    sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
-                    description: 'A medium to large field for visual content that is the central focus.',
-                    opts: {
-                        _rotation: -45,
-                    },
-                },
-            ]
-            },
-            {
-                viewType: ViewType.STATIC,
-                tl: [-0.7, 0.2],
-                br: [0.7, 0.46],
-                types: [TemplateFieldType.TEXT],
-                sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL],
-                description: 'A very small text field for one to a few words. A good caption for the image.',
-                opts: {
-                    backgroundColor: 'transparent',
-                    hCentering: 'h-center',
-                },
-            },
-            {
-                viewType: ViewType.STATIC,
-                tl: [-0.95, 0.5],
-                br: [0.95, 0.95],
-                types: [TemplateFieldType.TEXT],
-                sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE],
-                description: 'A medium to large text field for a thorough description of the image. ',
-                opts: {
-                    backgroundColor: 'transparent',
-                    text_fontColor: 'white',
-                },
-            },
-            {
-                viewType: ViewType.FREEFORM,
-                tl: [0.2, -1.32],
-                br: [1.8, -0.66],
-                opts: {
-                    backgroundColor: '#CEB155',
-                    _rotation: 45,
-                },
-                subfields: [
-                    {
-                        viewType: ViewType.DEC,
-                        tl: [-1, -.7],
-                        br: [1, -.625],
-                        opts: {
-                            backgroundColor: 'yellow',
-                        },
-                    },
-                ]
-            },
-            {
-                viewType: ViewType.FREEFORM,
-                tl: [-1.8, -1.32],
-                br: [-0.2, -0.66],
-                opts: {
-                    backgroundColor: '#CEB155',
-                    _rotation: 135,
-                },
-                subfields: [
-                    {
-                        viewType: ViewType.DEC,
-                        tl: [-1, -.7],
-                        br: [1, -.625],
-                        opts: {
-                            backgroundColor: 'yellow',
-                        },
-                    },
-                ]
-            },
-            {
-                viewType: ViewType.FREEFORM,
-                tl: [0.33, 0.75],
-                br: [1.66, 1.25],
-                opts: {
-                    backgroundColor: '#CEB155',
-                    _rotation: 135,
-                },
-                subfields: [
-                    {
-                        viewType: ViewType.DEC,
-                        tl: [-1, -.7],
-                        br: [1, -.625],
-                        opts: {
-                            backgroundColor: 'yellow',
-                        },
-                    },
-                ]
-            },
-            {
-                viewType: ViewType.FREEFORM,
-                tl: [-1.66, 0.75],
-                br: [-0.33, 1.25],
-                opts: {
-                    backgroundColor: '#CEB155',
-                    _rotation: 45,
-                },
-                subfields: [
-                    {
-                        viewType: ViewType.DEC,
-                        tl: [-1, -.7],
-                        br: [1, -.625],
-                        opts: {
-                            backgroundColor: 'yellow',
-                        },
-                    },
-                ]
-            },
-        ],
-    };
-
-    public static ThreeField002: FieldSettings = {
-        title: 'threefield002',
-        viewType: ViewType.FREEFORM,
-        tl: [0,0],
-        br: [477, 662],
-        opts: {
-            backgroundColor: '#9E9C95',
-        },
-        subfields: [
-            {
-                viewType: ViewType.STATIC,
-                tl: [-0.875, -0.9],
-                br: [0.875, 0.7],
-                types: [TemplateFieldType.VISUAL],
-                sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
-                description: 'A medium to large visual field for the main content of the template',
-                opts: {
-                    borderWidth: 15,
-                    borderColor: '#E0E0DA',
-                },
-            },
-            {
-                viewType: ViewType.STATIC,
-                tl: [0.1, 0.775],
-                br: [0.95, 0.975],
-                types: [TemplateFieldType.TEXT],
-                sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL],
-                description: 'A very small text field for one to a few words. The content should represent a general categorization of the image.',
-                opts: {
-                    backgroundColor: 'transparent',
-                    text_fontColor: '#AF0D0D',
-                    text_transform: 'uppercase',
-                    contentBold: true,
-                    hCentering: 'h-left',
-                },
-            },
-            {
-                viewType: ViewType.STATIC,
-                tl: [-0.95, 0.775],
-                br: [-0.1, 0.975],
-                types: [TemplateFieldType.TEXT],
-                sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL],
-                description: 'A very small text field for one to a few words. The content should contextualize field 2.',
-                opts: {
-                    backgroundColor: 'transparent',
-                    text_fontColor: 'black',
-                    hCentering: 'h-right',
-                },
-            },
-            {
-                viewType: ViewType.DEC,
-                tl: [-0.025, 0.8],
-                br: [0.025, 0.95],
-                opts: {
-                    backgroundColor: '#E0E0DA',
-                },
-            },
-        ],
-    };
-}
-
-
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/DecorationField.ts b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/DecorationField.ts
new file mode 100644
index 000000000..4f5ad89b6
--- /dev/null
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/DecorationField.ts
@@ -0,0 +1,11 @@
+import { DynamicField } from './DynamicField';
+import { FieldSettings, TemplateField } from './TemplateField';
+
+export class DecorationField extends DynamicField {
+    private constructor(settings: FieldSettings, parent?: TemplateField, id: number = 1) {
+        super(settings, parent, id);
+    }
+    static Create(settings: FieldSettings, id: number | undefined, parent?: TemplateField) {
+        return DynamicField.Create(settings, id, parent);
+    }
+}
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/DynamicField.ts b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/DynamicField.ts
new file mode 100644
index 000000000..0917093b1
--- /dev/null
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/DynamicField.ts
@@ -0,0 +1,164 @@
+import { reaction } from 'mobx';
+import { IDisposer } from 'mobx-utils';
+import { Doc, DocListCast } from '../../../../../../fields/Doc';
+import { DocData } from '../../../../../../fields/DocSymbols';
+import { List } from '../../../../../../fields/List';
+import { NumCast } from '../../../../../../fields/Types';
+import { Docs } from '../../../../../documents/Documents';
+import { DocumentType } from '../../../../../documents/DocumentTypes';
+import { FieldSettings, TemplateField, ViewType } from './TemplateField';
+
+export class DynamicField extends TemplateField {
+    protected _disposers: { [name: string]: IDisposer } = {};
+    protected _subfields: TemplateField[] | undefined;
+
+    protected constructor(settings: FieldSettings, parent?: TemplateField, id: number = 1) {
+        super(settings, parent, id);
+    }
+    static Create(settings: FieldSettings, id: number | undefined, parent?: TemplateField) {
+        const field = new DynamicField(settings, parent, id);
+        field._subfields = settings.subfields?.map((fieldSettings, index) => TemplateField.initField(fieldSettings, index, field)) || [];
+        field._renderDoc = field.initializeDocument(settings, field._subfields);
+        field._disposers.fieldList = reaction(() => DocListCast(field._renderDoc?.[Doc.LayoutFieldKey(field._renderDoc)]), field.handleFieldUpdate);
+        return field;
+    }
+
+    get getSubfields(): TemplateField[] {
+        return this._subfields ?? [];
+    }
+    get getAllSubfields() {
+        return (
+            this._subfields?.reduce((fields, field) => {
+                fields.push(field, ...((field as DynamicField).getAllSubfields ?? []));
+                return fields;
+            }, [] as TemplateField[]) ?? []
+        );
+    }
+
+    setSubFields = (fields: TemplateField[]) => (this._subfields = fields);
+
+    handleFieldUpdate = (newDocsList: Doc[]) => {
+        const currRenderedDocs = new Set(this._subfields?.filter(field => field.renderedDoc).map(field => field.renderedDoc!));
+        newDocsList.forEach(doc => !currRenderedDocs.has(doc) && this.addFieldFromDoc(doc));
+        currRenderedDocs.forEach(doc => {
+            if (!newDocsList.includes(doc)) {
+                this._subfields?.forEach(field => field.renderedDoc === doc && this.removeField(field));
+            }
+        });
+    };
+
+    addFieldFromDoc = (doc: Doc) => {
+        const par = this._renderDoc;
+        const settings: FieldSettings = {
+            tl: [Number(doc._x) / NumCast(par?._width, 1), Number(doc?._y) / NumCast(par?._height, 1)],
+            br: [(Number(doc._x) + Number(doc._width)) / NumCast(par?._width, 1), (Number(doc._y) + Number(doc._height)) / NumCast(par?._height, 1)],
+            viewType: doc.type === DocumentType.COL ? ViewType.FREEFORM : ViewType.STATIC,
+            opts: {},
+        };
+
+        this._subfields?.push(TemplateField.initField(settings, this._subfields?.length ?? 0, this));
+    };
+
+    addField = (field: TemplateField) => {
+        if (!this._subfields?.includes(field)) {
+            this._subfields?.push(field);
+            // Doc.SetContainer(field.Document, this.Document);
+        }
+    };
+
+    dispose = () => Object.values(this._disposers).forEach(disposer => disposer?.());
+
+    removeField = (field: TemplateField) => {
+        // var childDocs: Doc[] = DocListCast(this.Document[Doc.LayoutFieldKey(this.Document)]);
+        // this.Document[Doc.LayoutFieldKey(this.Document)] = new List<Doc>([...childDocs.splice(childDocs.indexOf(field.Document), 1)]);
+        this._subfields?.splice(this._subfields?.indexOf(field), 1);
+        (field as DynamicField).dispose?.();
+    };
+
+    // implement Field's abstract method for replacing a subfield with a new one
+    exchangeFields(newField: TemplateField, oldField: TemplateField) {
+        this._subfields?.splice(this._subfields?.indexOf(oldField), 1, newField);
+    }
+
+    get isContentField(): boolean {
+        return false;
+    }
+
+    // eslint-disable-next-line @typescript-eslint/no-unused-vars
+    setContent(content: string, type: ViewType) {}
+
+    getContent = () => '';
+
+    addChildToDocument = (doc: Doc) => this._renderDoc && Doc.SetContainer(doc, this._renderDoc);
+
+    matches = (): Array<number> => [];
+
+    async makeClone(parent?: DynamicField): Promise<TemplateField> {
+        const clone = (await super.makeClone(parent)) as unknown as DynamicField;
+        if (this._subfields) {
+            clone._subfields = await Promise.all(this._subfields.map(async cloneField => await cloneField.makeClone(clone)));
+        }
+        clone._renderDoc && (clone._renderDoc[DocData].data = new List<Doc>(clone._subfields?.filter(sub => sub.renderedDoc).map(sub => sub.renderedDoc!) ?? []));
+        return clone;
+    }
+
+    initializeDocument = (settings: FieldSettings, subFields: TemplateField[]) => {
+        const renderedSubfields = subFields?.filter(field => field.renderedDoc).map(field => field.renderedDoc!) ?? [];
+        settings.opts.title = settings.title;
+        switch (settings.viewType) {
+            case ViewType.CAROUSEL3D: return Docs.Create.Carousel3DDocument(renderedSubfields, settings.opts);
+            case ViewType.FREEFORM:   
+            default:                  return Docs.Create.FreeformDocument(renderedSubfields, settings.opts);
+        } // prettier-ignore
+    };
+}
+
+// export class DynamicField extends Field {
+//     protected subfields: Field[];
+
+//     protected Document!: Doc;
+
+//     constructor(settings: FieldSettings, id: number, parent?: Field) {
+//         super(settings, id, parent);
+//         this.subfields = this.setupSubfields(this);
+//         this.initializeDocument();
+//     }
+
+//     setContent = (content: string, type: ViewType) => { return };
+//     getContent = () => { return '' };
+//     get isContentField(): boolean { return false };
+
+//     addChildToDocument = (doc: Doc) => {
+//         Doc.SetContainer(doc, this.Document);
+//     }
+
+//     matches = (cols: Col[]): Array<number> => {
+//         return [];
+//     }
+
+//     initializeDocument = (): Doc => {
+//         let doc: Doc;
+//         const renderedSubfields: Doc[] = this.subfields.map(field => field.renderedDoc);
+//         switch (this.settings.viewType) {
+//             case ViewType.CAROUSEL3D:
+//                 doc = Docs.Create.Carousel3DDocument(renderedSubfields, {
+//                     title: this.title,
+//                 });
+//                 break;
+//             case ViewType.FREEFORM:
+//                 doc = Docs.Create.FreeformDocument(renderedSubfields, {
+//                     title: this.title,
+//                 });
+//                 break;
+//             default:
+//                 doc = Docs.Create.FreeformDocument(renderedSubfields, {
+//                     title: this.title,
+//                 });
+//             break;
+//         }
+
+//         this.Document = doc;
+//         return doc;
+//     }
+
+// }
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/StaticContentField.ts b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/StaticContentField.ts
new file mode 100644
index 000000000..b8839efab
--- /dev/null
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/StaticContentField.ts
@@ -0,0 +1,72 @@
+import { DocData } from '../../../../../../fields/DocSymbols';
+import { RichTextField } from '../../../../../../fields/RichTextField';
+import { ImageField } from '../../../../../../fields/URLField';
+import { Docs } from '../../../../../documents/Documents';
+import { FieldSettings, TemplateField, ViewType } from './TemplateField';
+import { TemplateFieldUtils } from './TemplateFieldUtils';
+
+export abstract class StaticContentField extends TemplateField {
+    protected _content: string = '';
+
+    getContent = () => this._content ?? 'unset';
+    get isContentField(): boolean {
+        return true;
+    }
+}
+
+export class ImageTemplateField extends StaticContentField {
+    private constructor(settings: FieldSettings, parent?: TemplateField, id: number = 1) {
+        super(settings, parent, id);
+    }
+    static Create(settings: FieldSettings, id: number | undefined, parent: TemplateField | undefined) {
+        const field = new ImageTemplateField(settings, parent, id);
+        field._renderDoc = field.initializeDocument(settings);
+        return field;
+    }
+
+    setContent(url: string, type?: ViewType) {
+        super.setContent(url, type);
+
+        if (type === ViewType.IMG || type === undefined) {
+            this._renderDoc && (this._renderDoc[DocData].data = new ImageField(url));
+            this._content = url;
+        } else {
+            this.changeFieldType(type).setContent(url, type);
+        }
+    }
+
+    initializeDocument = (settings: FieldSettings) => {
+        settings.opts.title = settings.title;
+        settings.opts._layout_fitWidth = false;
+
+        return Docs.Create.ImageDocument('', settings.opts);
+    };
+}
+
+export class TextTemplateField extends StaticContentField {
+    private constructor(settings: FieldSettings, parent?: TemplateField, id: number = 1) {
+        super(settings, parent, id);
+    }
+    static Create(settings: FieldSettings, id: number, parent?: TemplateField) {
+        const field = new TextTemplateField(settings, parent, id);
+        field._renderDoc = field.initializeDocument(settings);
+        field._renderDoc.text_fontSize = `${TemplateFieldUtils.calculateFontSize(field._dimensions?.width ?? 10, field._dimensions?.height ?? 10, '', true)}`;
+        return field;
+    }
+    setContent(text: string, type?: ViewType) {
+        super.setContent(text, type);
+
+        if (type === ViewType.TEXT || type === undefined) {
+            this._content = text;
+            this._renderDoc && (this._renderDoc[DocData].text = RichTextField.textToRtf(text));
+        } else {
+            this.changeFieldType(type).setContent(text, type);
+        }
+    }
+
+    initializeDocument = (settings: FieldSettings | undefined) => {
+        const opts = settings?.opts;
+        opts && (opts.title = settings?.title ?? '');
+        return Docs.Create.TextDocument('', opts);
+    };
+}
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/TemplateField.ts b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/TemplateField.ts
new file mode 100644
index 000000000..318bffde5
--- /dev/null
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/TemplateField.ts
@@ -0,0 +1,159 @@
+/* eslint-disable no-use-before-define */
+import { computed } from 'mobx';
+import { Doc } from '../../../../../../fields/Doc';
+import { DocData } from '../../../../../../fields/DocSymbols';
+import { Copy } from '../../../../../../fields/FieldSymbols';
+import { ObjectField } from '../../../../../../fields/ObjectField';
+import { DocumentOptions } from '../../../../../documents/Documents';
+import { Col } from '../DocCreatorMenu';
+import { TemplateFieldSize, TemplateFieldType } from '../TemplateBackend';
+
+export abstract class TemplateField {
+    /**
+     * Creates and initializes a new TemplateField based on the settings and parameters
+     *
+     * implemented in FieldUtils and assigned in main (to avoid import cycles)
+     *
+     * @param settings - specification of the field type and other parameters
+     * @param index -
+     * @param parent - TemplateField that contains the new field
+     * @param sameId -
+     * @returns TemplateField
+     */
+    static initField: (settings: FieldSettings | undefined, index: number | undefined, parent: TemplateField | undefined, sameId?: boolean) => TemplateField;
+
+    protected _parent?: TemplateField;
+    protected _id: number;
+    protected _title: string = '';
+    protected _settings: FieldSettings;
+    protected _renderDoc: Doc | undefined;
+    protected _dimensions: FieldDimensions | undefined;
+
+    constructor(settings: FieldSettings, parent?: TemplateField, id: number = 1) {
+        this._id = id;
+        this._parent = parent;
+        this._settings = settings;
+        this._title = settings.title ?? '';
+        this._dimensions = this.getLocalDimensions(this._settings, this._parent?.getDimensions);
+        this.applyBasicOpts(this._dimensions, settings);
+        return this;
+    }
+
+    get renderedDoc() {
+        return this._renderDoc;
+    }
+    get getDimensions() {
+        return this._dimensions;
+    }
+    get getID() {
+        return this._id;
+    }
+    get getDescription(): string {
+        return this._settings?.description ?? '';
+    }
+    get viewType(): ViewType | undefined {
+        return this._settings?.viewType;
+    }
+
+    setTitle = (title: string) => {
+        this._title = title;
+        this._renderDoc && (this._renderDoc.title = title);
+    };
+    getTitle = () => this._title;
+
+    abstract get isContentField(): boolean;
+    setContent(content: string, type?: ViewType) {
+        this._settings && (this._settings.viewType = type ?? this._settings.viewType);
+    }
+
+    abstract getContent(): string;
+
+    async makeClone(parent?: TemplateField): Promise<TemplateField> {
+        const clone = TemplateField.initField(this._settings, this._id, parent, true); // create a value for this.Document/subfields that we want to ignore
+        clone._renderDoc = this._renderDoc ? (await Doc.MakeClone(this._renderDoc)).clone : undefined;
+        clone._title = this._title;
+        clone._dimensions = this._dimensions;
+        return clone;
+    }
+
+    @computed get documentOptions(): DocumentOptions {
+        const opts: DocumentOptions = {};
+        Object.assign(opts, this._renderDoc?.[DocData]);
+        Object.entries(opts).forEach(([key, field]) => {
+            Object.assign(opts, { [key]: field instanceof Object ? ObjectField.MakeCopy(field) : field[Copy]() });
+        });
+        return opts;
+    }
+    exchangeFields(newField: TemplateField, oldField: TemplateField) {
+        throw new Error('Only DynamicField can exchange fields.' + newField._title + ' ' + oldField._title);
+    }
+    // eslint-disable-next-line @typescript-eslint/no-unused-vars
+    changeFieldType = (newType: ViewType): TemplateField => {
+        const newField = TemplateField.initField(this._settings, this._id, this._parent, true);
+        this._parent?.exchangeFields(newField, this);
+        return newField;
+    };
+
+    matches = (cols: Col[]): number[] => {
+        const colMatchesField = (col: Col) => (this._settings?.sizes?.some(size => col.sizes?.includes(size)) && this._settings.types?.includes(col.type)) ?? false;
+
+        const matches: Array<number> = [];
+        cols.forEach((col, v) => colMatchesField(col) && matches.push(v));
+        return matches;
+    };
+
+    private getLocalDimensions = (coords: { tl: [number, number]; br: [number, number] }, parentDimensions?: FieldDimensions): FieldDimensions => {
+        if (!parentDimensions) {
+            return { width: coords.br[0] - coords.tl[0], height: coords.br[1] - coords.tl[1], coord: { x: coords.tl[0], y: coords.tl[1] } };
+        }
+        const l = (coords.tl[0] * parentDimensions.width) / 2;
+        const t = coords.tl[1] * parentDimensions.height / 2; //prettier-ignore
+        const r = (coords.br[0] * parentDimensions.width) / 2;
+        const b = coords.br[1] * parentDimensions.height / 2; //prettier-ignore
+        return { width: r-l, height: b-t, coord: { x: l, y: t } }; //prettier-ignore
+    };
+
+    private applyBasicOpts = (dimensions: FieldDimensions, settings: FieldSettings | undefined) => {
+        const opts: DocumentOptions = settings?.opts ?? {};
+        opts.isDefaultTemplateDoc ??= true;
+        opts._layout_hideScroll ??= true;
+        opts.x ??= dimensions.coord.x;
+        opts.y ??= dimensions.coord.y;
+        opts._height ??= dimensions.height;
+        opts._width ??= dimensions.width;
+        opts._nativeWidth ??= dimensions.width;
+        opts._nativeHeight ??= dimensions.height;
+        opts._layout_nativeDimEditable ??= true;
+    };
+}
+
+export type FieldSettings = {
+    tl: [number, number];
+    br: [number, number];
+    opts: DocumentOptions;
+    viewType: ViewType;
+    title?: string;
+    subfields?: FieldSettings[];
+    types?: TemplateFieldType[];
+    sizes?: TemplateFieldSize[];
+    description?: string;
+};
+
+export enum ViewType {
+    CAROUSEL3D = 'carousel3d',
+    FREEFORM = 'freeform',
+    STATIC = 'static',
+    DEC = 'decoration',
+    IMG = 'image',
+    TEXT = 'text',
+}
+
+export type FieldDimensions = {
+    width: number;
+    height: number;
+    coord: { x: number; y: number };
+};
+
+export type FieldTree = {
+    node: { field: TemplateField; subfields: FieldTree[] };
+};
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/TemplateFieldUtils.ts b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/TemplateFieldUtils.ts
new file mode 100644
index 000000000..c38d769cd
--- /dev/null
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/TemplateFieldUtils.ts
@@ -0,0 +1,71 @@
+import { DecorationField } from './DecorationField';
+import { DynamicField } from './DynamicField';
+import { ImageTemplateField, TextTemplateField } from './StaticContentField';
+import { FieldSettings, TemplateField, ViewType } from './TemplateField';
+
+export class TemplateFieldUtils {
+    /**
+     * Creates and initializes a new TemplateField based on the settings and parameters
+     *
+     * implements Field.initField ... see main.tsx
+     *
+     * @param settings - specification of the field type and other parameters
+     * @param index -
+     * @param parent - TemplateField that contains the new field
+     * @param sameId -
+     * @returns TemplateField
+     */
+    public static initField = (settings: FieldSettings, index: number, parent: TemplateField | undefined, sameId: boolean = false): TemplateField => {
+        const id = sameId ? index : parent ? Number(`${parent.getID}${index}`) : 1;
+        switch (settings?.viewType) {
+            case ViewType.FREEFORM:
+            case ViewType.CAROUSEL3D: return DynamicField.Create(settings, id, parent);
+            case ViewType.IMG:        return ImageTemplateField.Create(settings, id, parent);
+            case ViewType.TEXT:       return TextTemplateField.Create(settings, id, parent);
+            case ViewType.DEC:        return DecorationField.Create(settings, id, parent);
+            default:                  return TextTemplateField.Create(settings, id, parent);
+        } // prettier-ignore
+    };
+
+    // eslint-disable-next-line @typescript-eslint/no-unused-vars
+    public static calculateFontSize = (contWidth: number, contHeight: number, text: string, uppercase: boolean): number => {
+        const words: string[] = text.split(/\s+/).filter(Boolean);
+
+        let currFontSize = 1;
+        let rowsCount = 1;
+        let currTextHeight = currFontSize * rowsCount * 2;
+
+        while (currTextHeight <= contHeight) {
+            let wordIndex = 0;
+            let currentRowWidth = 0;
+            let wordsInCurrRow = 0;
+            rowsCount = 1;
+
+            while (wordIndex < words.length) {
+                const word = words[wordIndex];
+                const wordWidth = word.length * currFontSize * 0.7;
+
+                if (currentRowWidth + wordWidth <= contWidth) {
+                    currentRowWidth += wordWidth;
+                    ++wordsInCurrRow;
+                } else {
+                    if (words.length !== 1 && words.length > wordsInCurrRow) {
+                        rowsCount++;
+                        currentRowWidth = wordWidth;
+                        wordsInCurrRow = 1;
+                    } else {
+                        break;
+                    }
+                }
+
+                wordIndex++;
+            }
+
+            currTextHeight = rowsCount * currFontSize * 2;
+
+            currFontSize += 1;
+        }
+
+        return currFontSize - 1;
+    };
+}
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.ts b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.ts
new file mode 100644
index 000000000..1959cf9d6
--- /dev/null
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.ts
@@ -0,0 +1,33 @@
+import { makeAutoObservable } from 'mobx';
+import { Col } from './DocCreatorMenu';
+import { FieldSettings } from './TemplateFieldTypes/TemplateField';
+import { Template } from './Template';
+
+export class TemplateManager {
+    templates: Template[] = [];
+
+    constructor(templateSettings: FieldSettings[]) {
+        makeAutoObservable(this);
+        this.templates = this.initializeTemplates(templateSettings);
+    }
+
+    initializeTemplates = (templateSettings: FieldSettings[]): Template[] => {
+        const initializedTemplates: Template[] = [];
+        templateSettings.forEach(settings => initializedTemplates.push(new Template(settings)));
+        return initializedTemplates;
+    };
+
+    getValidTemplates = (cols: Col[]): Template[] => {
+        console.log('called in manager with templates: ', this.templates);
+        return this.templates.filter(template => template.isValidTemplate(cols));
+    };
+
+    addTemplate = (newTemplate: Template) => {
+        this.templates.push(newTemplate);
+    };
+
+    removeTemplate = (template: Template) => {
+        this.templates.splice(this.templates.indexOf(template), 1);
+        template.cleanup();
+    };
+}
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.tsx
deleted file mode 100644
index 09b4ce029..000000000
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.tsx
+++ /dev/null
@@ -1,34 +0,0 @@
-import { makeAutoObservable } from "mobx";
-import { Col } from "./DocCreatorMenu";
-import { FieldSettings } from "./FieldTypes/Field";
-import { Template } from "./Template";
-
-export class TemplateManager {
-
-    templates: Template[] = [];
-
-    constructor(templateSettings: FieldSettings[]) {
-        makeAutoObservable(this);
-        this.templates = this.initializeTemplates(templateSettings);
-    }
-
-    initializeTemplates = (templateSettings: FieldSettings[]): Template[] => {
-        const initializedTemplates: Template[] = [];
-        templateSettings.forEach(settings => initializedTemplates.push(new Template(settings)));
-        return initializedTemplates;
-    }
-
-    getValidTemplates = (cols: Col[]): Template[] => {
-        console.log('called in manager with templates: ', this.templates)
-        return this.templates.filter(template => template.isValidTemplate(cols));
-    }
-
-    addTemplate = (newTemplate: Template) =>{
-        this.templates.push(newTemplate);
-    }
-
-    removeTemplate = (template: Template) => {
-        this.templates.splice(this.templates.indexOf(template), 1);
-        template.cleanup();
-    }
-}
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2

