From e730ae254cd16559fdb7ca67ff1b4ed6767ab7e5 Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Thu, 17 Oct 2024 03:18:42 -0400
Subject: work on getting collections to render directly into the layout editor

---
 .../DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx   | 424 ++++++++++++++-------
 1 file changed, 280 insertions(+), 144 deletions(-)

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

diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
index 91c86bef1..8977a282e 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
@@ -31,11 +31,12 @@ import { Transform } from '../../../../util/Transform';
 import { IconProp } from '@fortawesome/fontawesome-svg-core';
 
 export enum LayoutType {
-    Stacked = 'stacked',
-    Grid = 'grid',
+    STACKED = 'stacked',
+    GRID = 'grid',
     Row = 'row',
     Column = 'column',
     Custom = 'custom',
+    CAROUSEL3D = 'carousel3d'
 }
 
 @observer
@@ -46,12 +47,15 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
     private _ref: HTMLDivElement | null = null;
 
+    @observable _fullyRenderedDocs: Doc[] = [];
+    @observable _renderedDocCollection: Doc | undefined = undefined;
+
     @observable _templateDocs: Doc[] = [];
     @observable _selectedTemplate: Doc | undefined = undefined;
     @observable _columns: Col[] = [];
     @observable _selectedCols: { title: string; type: string; desc: string }[] | undefined = [];
 
-    @observable _layout: { type: LayoutType; yMargin: number; xMargin: number; columns?: number; repeat: number } = { type: LayoutType.Grid, yMargin: 0, xMargin: 0, repeat: 0 };
+    @observable _layout: { type: LayoutType; yMargin: number; xMargin: number; columns?: number; repeat: number } = { type: LayoutType.GRID, yMargin: 0, xMargin: 0, repeat: 0 };
     @observable _layoutPreview: boolean = true;
     @observable _layoutPreviewScale: number = 1;
     @observable _savedLayouts: DataVizTemplateLayout[] = [];
@@ -112,14 +116,16 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     @computed get rowsCount() {
         switch (this._layout.type) {
             case LayoutType.Row:
-            case LayoutType.Stacked:
+            case LayoutType.STACKED:
                 return 1;
             case LayoutType.Column:
                 return this.docsToRender.length;
-            case LayoutType.Grid:
+            case LayoutType.GRID:
                 return Math.ceil(this.docsToRender.length / (this._layout.columns ?? 1)) ?? 0;
+            case LayoutType.CAROUSEL3D:
+                return 1;
             default:
-                return 0;
+                return 1;
         }
     }
 
@@ -128,12 +134,14 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
             case LayoutType.Row:
                 return this.docsToRender.length;
             case LayoutType.Column:
-            case LayoutType.Stacked:
+            case LayoutType.STACKED:
                 return 1;
-            case LayoutType.Grid:
+            case LayoutType.GRID:
                 return this._layout.columns ?? 0;
+            case LayoutType.CAROUSEL3D:
+                return 1.75;
             default:
-                return 0;
+                return 1;
         }
     }
 
@@ -363,6 +371,9 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         } else {
             this._selectedTemplate = template;
             MakeTemplate(template);
+            const templateInfo: DataVizTemplateInfo = { doc: template, layout: this._layout, referencePos: { x: this._pageX + 450, y: this._pageY }, columns: this.columnsCount };
+            this._fullyRenderedDocs = this._dataViz?.createDocsFromTemplate(templateInfo, true) ?? [];
+            this.updateRenderedDocCollection();
         }
     };
 
@@ -1143,7 +1154,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                 return <div className="docCreatorMenu-configuration-bar">{optionInput('arrows-left-right', this.updateXMargin, this._layout.xMargin, '0')}</div>;
             case LayoutType.Column:
                 return <div className="docCreatorMenu-configuration-bar">{optionInput('arrows-up-down', this.updateYMargin, this._layout.yMargin, '1')}</div>;
-            case LayoutType.Grid:
+            case LayoutType.GRID:
                 return (
                     <div className="docCreatorMenu-configuration-bar">
                         {optionInput('arrows-up-down', this.updateYMargin, this._layout.xMargin, '2')}
@@ -1151,7 +1162,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                         {optionInput('table-columns', this.updateColumns, this._layout.columns, '4', true)}
                     </div>
                 );
-            case LayoutType.Stacked:
+            case LayoutType.STACKED:
                 return null;
             default:
                 break;
@@ -1164,6 +1175,86 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
     screenToLocalTransform = () => this._props.ScreenToLocalTransform();
 
+    applyLayout = (collection: Doc, docs: Doc[]) => {
+        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 startX: number = -Number(collection._width)/2;
+        const startY: number = -Number(collection._height)/2;
+        const docHeight: number = Number(docs[0]._height);
+        const docWidth: number = Number(docs[0]._width);
+
+        if (columns === 0 || docs.length === 0){
+            return;
+        }
+
+        let i: number = 0;
+        let docsChanged: number = 0;
+        let curX: number = startX;
+        let curY: number = startY;
+
+        while (docsChanged < docs.length) {
+            while (i < columns && docsChanged < docs.length) {
+                docs[docsChanged].x = curX;
+                docs[docsChanged].y = curY;
+                curX += docWidth + xGap;
+                ++docsChanged;
+                ++i;
+            }
+            i = 0;
+            curX = startX;
+            curY += docHeight + yGap;
+        }
+    };
+
+    /**
+     * Updates the preview that shows how all docs will be rendered in the chosen collection type.
+    @type the type of collection the docs should render to (ie. freeform, carousel, card)
+     */
+    updateRenderedDocCollection = () => {
+        if (!this._fullyRenderedDocs) return;
+
+        const layout = this._layout;
+
+        const docHeight: number = Number(this._fullyRenderedDocs[0]._height);
+        const docWidth: number = Number(this._fullyRenderedDocs[0]._width);
+        const horizontalSpan: number = (docWidth + layout.xMargin) * (this.columnsCount) - layout.xMargin;
+        const verticalSpan: number = (docHeight + layout.yMargin) * (this.rowsCount) - layout.yMargin;
+        const largerSpan: number = horizontalSpan > verticalSpan ? horizontalSpan : verticalSpan;
+
+        const collectionFactory = (): (docs: Doc[], options: DocumentOptions) => Doc => {
+            switch (this._layout.type) {
+                case LayoutType.CAROUSEL3D:
+                    return Docs.Create.Carousel3DDocument;
+                case LayoutType.GRID:
+                    return Docs.Create.FreeformDocument;
+                default:
+                    return Docs.Create.FreeformDocument;
+            }
+        }
+
+        const docWithBasicOpts: Doc = collectionFactory()(this._fullyRenderedDocs, {
+            isDefaultTemplateDoc: true,
+            x: this._pageX,
+            y: this._pageY,
+            _height: verticalSpan,
+            _width: horizontalSpan,
+            title: 'title',
+            backgroundColor: 'gray',
+        });
+
+        this.applyLayout(docWithBasicOpts, this._fullyRenderedDocs);
+
+        const wrapper: Doc = Docs.Create.FreeformDocument([docWithBasicOpts], { _height: NumListCast(docWithBasicOpts._height)[0], _width: NumListCast(docWithBasicOpts._width)[0], title: ''});
+
+        const mainCollection = this._dataViz?.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionFreeFormView;
+        mainCollection.addDocument(docWithBasicOpts);
+
+        this._renderedDocCollection = wrapper;
+    }
+
     layoutPreviewContents = (outerSpan: number, altLayout?: DataVizTemplateLayout, small: boolean = false, id?: number) => {
         const doc: Doc | undefined = altLayout ? altLayout.template : this._selectedTemplate;
         if (!doc) return;
@@ -1175,37 +1266,46 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         const horizontalSpan: number = (docWidth + layout.xMargin) * (altLayout ? altLayout.columns : this.columnsCount) - layout.xMargin;
         const verticalSpan: number = (docHeight + layout.yMargin) * (altLayout ? altLayout.rows : this.rowsCount) - layout.yMargin;
         const largerSpan: number = horizontalSpan > verticalSpan ? horizontalSpan : verticalSpan;
+        
         const scaledDown = (input: number) => {
             return input / ((largerSpan / outerSpan) * this._layoutPreviewScale);
         };
         const fontSize = Math.min(scaledDown(docWidth / 3), scaledDown(docHeight / 3));
 
+
+
         return (
-            // <div className='divvv' style={{width: 100, height: 100, border: `1px solid white`}}>
-            //     <CollectionFreeFormView
-            //         // eslint-disable-next-line react/jsx-props-no-spreading
-            //         {...this._props}
-            //         Document={new Doc()}
-            //         isContentActive={returnFalse}
-            //         setContentViewBox={emptyFunction}
-            //         NativeWidth={() => 100}
-            //         NativeHeight={() => 100}
-            //         pointerEvents={SnappingManager.IsDragging ? returnAll : returnNone}
-            //         isAnnotationOverlay
-            //         isAnnotationOverlayScrollable
-            //         childDocumentsActive={returnFalse}
-            //         fieldKey={this._props.fieldKey + '_annotations'}
-            //         dropAction={dropActionType.move}
-            //         select={emptyFunction}
-            //         addDocument={returnFalse}
-            //         removeDocument={returnFalse}
-            //         moveDocument={returnFalse}
-            //         renderDepth={this._props.renderDepth + 1}>
-            //         {null}
-            //     </CollectionFreeFormView>
-            // </div>
             <div className="docCreatorMenu-layout-preview-window-wrapper" id={String(id) ?? undefined}>
-                <div className="docCreatorMenu-zoom-button-container">
+                <CollectionFreeFormView
+                    Document={this._renderedDocCollection ?? new Doc()}
+                    docViewPath={returnEmptyDocViewList}
+                    childLayoutTemplate={() => Cast(doc.childLayoutTemplate, Doc, null)}
+                    isContentActive={emptyFunction}
+                    isAnyChildContentActive={() => true}
+                    select={emptyFunction}
+                    isSelected={returnFalse}
+                    fieldKey={Doc.LayoutFieldKey(doc)}
+                    addDocument={returnFalse}
+                    moveDocument={returnFalse}
+                    removeDocument={returnFalse}
+                    PanelWidth={() => this._menuDimensions.width - 10}
+                    PanelHeight={() => this._menuDimensions.height - 60}
+                    ScreenToLocalTransform={() => new Transform(-this._pageX - 5,-this._pageY - 35, 1)}
+                    renderDepth={5}
+                    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={returnTrue}
+                    xPadding={0}
+                    yPadding={0}
+                />
+                {/* <div className="docCreatorMenu-zoom-button-container">
                     <button className="docCreatorMenu-zoom-button" onPointerDown={e => this.setUpButtonClick(e, () => runInAction(() => (this._layoutPreviewScale *= 1.25)))}>
                         <FontAwesomeIcon icon={'minus'} />
                     </button>
@@ -1255,7 +1355,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                             ))
                         )}
                     </div>
-                }
+                } */}
             </div>
         );
     };
@@ -1271,7 +1371,10 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                     onPointerDown={e =>
                         this.setUpButtonClick(e, () => {
                             specialFunc?.();
-                            runInAction(() => (this._layout.type = option));
+                            runInAction(() => {
+                                this._layout.type = option;
+                                this.updateRenderedDocCollection();
+                            });
                         })
                     }>
                     {option}
@@ -1304,12 +1407,13 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                     <div className="docCreatorMenu-dropdown-hoverable">
                         <div className="docCreatorMenu-option-title">{this._layout.type ? this._layout.type.toUpperCase() : 'Choose Layout'}</div>
                         <div className="docCreatorMenu-dropdown-content">
-                            {layoutOption(LayoutType.Stacked)}
-                            {layoutOption(LayoutType.Grid, undefined, () => {
+                            {layoutOption(LayoutType.STACKED)}
+                            {layoutOption(LayoutType.GRID, undefined, () => {
                                 if (!this._layout.columns) this._layout.columns = Math.ceil(Math.sqrt(this.docsToRender.length));
                             })}
                             {layoutOption(LayoutType.Row)}
                             {layoutOption(LayoutType.Column)}
+                            {layoutOption(LayoutType.CAROUSEL3D)}
                             {layoutOption(LayoutType.Custom, { borderBottom: `0px` })}
                         </div>
                     </div>
@@ -1367,7 +1471,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                                     clickEv.stopPropagation();
                                     if (!this._selectedTemplate) return;
                                     const templateInfo: DataVizTemplateInfo = { doc: this._selectedTemplate, layout: this._layout, referencePos: { x: this._pageX + 450, y: this._pageY }, columns: this.columnsCount };
-                                    this._dataViz?.createDocsFromTemplate(templateInfo);
+                                    this._fullyRenderedDocs = this._dataViz?.createDocsFromTemplate(templateInfo) ?? [];
                                 }, 'make docs')
                             )
                         }>
@@ -1642,105 +1746,40 @@ type FieldSettings = {
     tl: [number, number];
     br: [number, number];
     opts: FieldOpts;
-    subfields?: Field[];
+    subfields?: FieldSettings[];
     types?: TemplateFieldType[];
     sizes?: TemplateFieldSize[];
+    isDecoration?: boolean;
     description?: string;
 };
 
-interface ConstructedField {
-    renderToDoc: (content: FieldType, doc: Doc) => Doc;
-    validSubfieldGroups: () => Field[];
-}
-
-class Field {
-    settings: FieldSettings;
-    parent: Field;
-
-    constructor(settings: FieldSettings, parent: Field, ) {
-        this.settings = settings;
-        this.parent = parent;
-    }
-
-    private 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.5;
-                //console.log(wordWidth)
-
-                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;
-    };
-
-    private getDimensions = (coords: { tl: [number, number]; br: [number, number] }, parentWidth: number, parentHeight: number): { width: number; height: number; coord: { x: number; y: number } } => {
-        const l = (coords.tl[0] * parentHeight) / 2;
-        const t = coords.tl[1] * parentWidth / 2; //prettier-ignore
-        const r = (coords.br[0] * parentHeight) / 2;
-        const b = coords.br[1] * parentWidth / 2; //prettier-ignore
-        const width = r - l;
-        const height = b - t;
-        const coord = { x: l, y: t };
-        return { width, height, coord };
-    };
-
-    private docWithBasicOpts = (factory: (children: unknown, options: DocumentOptions) => Doc, settings: FieldSettings): Doc => {
-        const x = settings.tl[0];
-        const y = settings.tl[1];
-        const height = settings.
-        return factory([], {...})
-    }
-}
-
-class TextField implements Field {
-    settings: FieldSettings;
-    parent: Field;
-
-    constructor(settings: FieldSettings, parent: Field) {
-        this.settings = settings;
-        this.parent = parent;
-    }
-
-    renderToDoc = (content: FieldType, doc: Doc): Doc => {
-
-        return new Doc;
-    }
-
-    validSubfieldGroups = () => {
-        return [];
-    }
-}
+// class ContentField implements Field {
+//     tl: [number, number];
+//     br: [number, number];
+//     opts: FieldOpts;
+//     subfields?: Field[];
+//     types?: TemplateFieldType[];
+//     sizes?: TemplateFieldSize[];
+//     description?: string;
+
+//     constructor( tl: [number, number], br: [number, number],
+//                         opts: FieldOpts, subfields?: Field[],
+//                         types?: TemplateFieldType[],
+//                         sizes?: TemplateFieldSize[],
+//                         description?: string) {
+//         this.tl = tl;
+//         this.br = br;
+//         this.opts = opts;
+//         this.subfields = subfields;
+//         this.types = types;
+//         this.sizes = sizes;
+//         this.description = description;
+//     }
+
+//     render = (content: any): Doc => {
+//         return new Doc;
+//     }
+// }
 
 type DecorationField = FieldSettings;
 
@@ -1954,6 +1993,66 @@ export class TemplateLayouts {
         ],
     };
 
+    // 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: TemplateDocInfos = {
         title: 'fourfield4',
         width: 414,
@@ -2232,18 +2331,9 @@ export class FieldUtils {
         return { width, height, coord };
     };
 
-    public static docWithBasicOpts = (factory: (children: unknown, options: DocumentOptions) => Doc, settings: FieldSettings): Doc => {
-        const x = settings.tl[0];
-        const y = settings.tl[1];
-        const height = settings.
-        return factory([], {...})
-    }
-
     public static FreeformField = (coords: { tl: [number, number]; br: [number, number] }, parentWidth: number, parentHeight: number, title: string, content: string, opts: FieldOpts) => {
         const { width, height, coord } = FieldUtils.getDimensions(coords, parentWidth, parentHeight);
 
-        
-
         const docWithBasicOpts = Docs.Create.FreeformDocument([], {
             isDefaultTemplateDoc: true,
             _height: height,
@@ -2325,4 +2415,50 @@ export class FieldUtils {
     };
 }
 
-
+//     public static FourField002: TemplateDocInfos = {
+//         width: 450,
+//         height: 600,
+//         fields: [{
+//             tl: [-.6, -.9],
+//             br: [.6, -.8],
+//             types: [FieldType.TEXT],
+//             sizes: [FieldSize.TINY]
+//         }, {
+//             tl: [-.9, -.7],
+//             br: [.9, .2],
+//             types: [FieldType.TEXT, FieldType.VISUAL],
+//             sizes: [FieldSize.MEDIUM, FieldSize.LARGE, FieldSize.HUGE]
+//         }, {
+//             tl: [-.9, .3],
+//             br: [-.05, .9],
+//             types: [FieldType.TEXT],
+//             sizes: [FieldSize.TINY]
+//         }, {
+//             tl: [.05, .3],
+//             br: [.9, .9],
+//             types: [FieldType.TEXT, FieldType.VISUAL],
+//             sizes: [FieldSize.MEDIUM, FieldSize.LARGE, FieldSize.HUGE]
+//         }]
+//     };
+
+//     public static TwoFieldPlusCarousel: TemplateDocInfos = {
+//         width: 500,
+//         height: 600,
+//         fields: [{
+//             tl: [-.9, -.99],
+//             br: [.9, -.7],
+//             types: [FieldType.TEXT],
+//             sizes: [FieldSize.TINY]
+//         }, {
+//             tl: [-.9, -.65],
+//             br: [.9, .35],
+//             types: [],
+//             sizes: []
+//         }, {
+//             tl: [-.9, .4],
+//             br: [.9, .95],
+//             types: [FieldType.TEXT],
+//             sizes: [FieldSize.TINY]
+//         }]
+//     };
+//  }
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2

