diff options
Diffstat (limited to 'src')
12 files changed, 864 insertions, 635 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 317bb7feb..f5ea849ae 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -290,6 +290,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 64416c26d..9e5dbe967 100644 --- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx +++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx @@ -1,5 +1,5 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { Colors } from '@dash/components'; +import { Colors } from 'browndash-components'; import { action, computed, makeObservable, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import { IDisposer } from 'mobx-utils'; @@ -7,7 +7,7 @@ import * as React from 'react'; import ReactLoading from 'react-loading'; import { ClientUtils, returnEmptyFilter, returnFalse, setupMoveUpEvents } from '../../../../../ClientUtils'; import { emptyFunction } from '../../../../../Utils'; -import { Doc, NumListCast, StrListCast, returnEmptyDoclist } from '../../../../../fields/Doc'; +import { Doc, DocListCast, FieldType, NumListCast, StrListCast, returnEmptyDoclist } from '../../../../../fields/Doc'; import { Id } from '../../../../../fields/FieldSymbols'; import { ImageCast, StrCast } from '../../../../../fields/Types'; import { ImageField } from '../../../../../fields/URLField'; @@ -28,7 +28,9 @@ import { Transform } from '../../../../util/Transform'; 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'; +import { DocData } from '../../../../../fields/DocSymbols'; import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { Upload } from '../../../../../server/SharedMediaTypes'; @@ -72,18 +74,19 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps> // eslint-disable-next-line no-use-before-define static Instance: DocCreatorMenu; + private DEBUG_MODE: boolean = false; + private _disposers: { [name: string]: IDisposer } = {}; private _ref: HTMLDivElement | null = null; 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[] = []; @observable _selectedTemplate: Template | undefined = undefined; @observable _currEditingTemplate: Template | undefined = undefined; @@ -91,15 +94,14 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps> @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; @observable _GPTLoading: boolean = false; + @observable _DOCCC: Doc | undefined; @observable _pageX: number = 0; @observable _pageY: number = 0; @@ -135,31 +137,26 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps> this._dataViz = dataViz; this._selectedTemplate = undefined; this._renderedDocCollection = undefined; - this._renderedDocCollectionPreview = undefined; this._fullyRenderedDocs = []; - this._suggestedTemplatePreviews = []; this._suggestedTemplates = []; this._userCreatedFields = []; }; @action addUserTemplate = (template: Template) => { - this._userTemplates.push({ template: template.cloneBase(), doc: template.getRenderedDoc() }); + this._userTemplates.push(template); }; @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 - }; + this._userTemplates.splice(this._userTemplates.indexOf(template), 1); + } @action setSuggestedTemplates = (templates: Template[]) => { - this._suggestedTemplates = templates; - this._suggestedTemplatePreviews = templates.map(template => {return {template: template, doc: template.getRenderedDoc()}}); //prettier-ignore + this._suggestedTemplates = templates; //prettier-ignore }; @computed get docsToRender() { - return this._selectedTemplate ? NumListCast(this._dataViz?.layoutDoc.dataViz_selectedRows) : []; + if (this.DEBUG_MODE) { + return [1, 2, 3, 4]; + } else { + return this._selectedTemplate ? NumListCast(this._dataViz?.layoutDoc.dataViz_selectedRows) : []; + } } @computed get rowsCount() { @@ -374,15 +371,20 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps> return undefined; } + @action updateRenderedPreviewCollection = async (template: Template) => { + this._fullyRenderedDocs = await this.createDocsFromTemplate(template) ?? []; + console.log(this._fullyRenderedDocs); + 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); } }; @@ -403,6 +405,34 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps> Doc.UnBrushDoc(doc); }; + testTemplate = async () => { + + this._suggestedTemplates = this.templateManager.templates; //prettier-ignore + + //console.log(this.templateManager.templates) + + // const mainCollection = this._dataViz?.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionFreeFormView; + + // this.templateManager.templates.forEach(template => { + // const doc = template.mainField.renderedDoc(); + // mainCollection.addDocument(doc); + // }) + + // this.forceUpdate(); + + // try { + // const res = await gptImageCall('Image of panda eating a cookie'); + + // if (res) { + // const result = await Networking.PostToServer('/uploadRemoteImage', { sources: res }); + + // console.log(result); + // } + // } catch (e) { + // console.log(e); + // } + }; + @action addField = () => { const newFields: Col[] = this._userCreatedFields.concat([{ title: '', type: TemplateFieldType.UNSET, desc: '', sizes: [] }]); this._userCreatedFields = newFields; @@ -515,7 +545,7 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps> 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; }); @@ -555,15 +585,14 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps> const brokenDownAssignments: [Template, { [fieldID: number]: Col }][] = []; Object.entries(assignments).forEach(([tempTitle, assignment]) => { - const template = templates.filter(t => t.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]) => { 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 ? 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); @@ -585,16 +614,25 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps> }; generatePresetTemplates = async () => { - this._dataViz?.updateColDefaults(); - const cols = this.fieldsInfos; - const templates = this.templateManager.getValidTemplates(cols); + const templates: Template[] = []; - const assignments: [Template, { [field: number]: Col }][] = await this.assignColsToFields(templates, cols); + if (this.DEBUG_MODE) { + templates.push(...this.templateManager.templates) + } else { + this._dataViz?.updateColDefaults(); + + const cols = this.fieldsInfos; + templates.push(...this.templateManager.getValidTemplates(cols)); + + const assignments: [Template, { [field: number]: Col }][] = await this.assignColsToFields(templates, cols); - const renderedTemplatePromises: Promise<Template | undefined>[] = assignments.map(([template, asns]) => this.applyGPTContentToTemplate(template, asns)); + const renderedTemplatePromises: Promise<Template | undefined>[] = assignments.map(([template, assignments]) => this.applyGPTContentToTemplate(template, assignments)); - await Promise.all(renderedTemplatePromises); + const renderedTemplates: (Template | undefined)[] = await Promise.all(renderedTemplatePromises); + } + + templates.forEach(template => template.mainField.initializeDocument()) setTimeout(() => { this.setSuggestedTemplates(templates); @@ -607,8 +645,8 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps> const url = await this.generateGPTImage(prompt); const field: Field = template.getFieldByID(Number(fieldNum)); - field.setContent(url ?? '', FieldContentType.IMAGE); - field.setTitle(column.title); + field.setContent(url ?? '', ViewType.IMG); + field.setTitle(col.title); }; const fieldContent: string = template.compiledContent; @@ -656,14 +694,16 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps> const res = await gptAPICall(`${++this._callCount}: ${prompt}`, GPTCallType.FILL); + // console.log('prompt: ', prompt, ' response: ', res); + 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 column = this.getColByTitle(title); - field.setContent(info.content ?? '', FieldContentType.STRING); - field.setTitle(column.title); + field.setContent(info.content ?? '', ViewType.TEXT); + field.setTitle(col.title); }); } } catch (err) { @@ -691,61 +731,56 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps> return values; }); + + const processContent = async (content: {[title: string]: string}) => { - const processContent = async (content: { [title: string]: string }) => { - const templateCopy = template.cloneBase(); - - fields - .filter(title => title) - .forEach(title => { - const field = templateCopy.getFieldByTitle(title); - if (field === undefined) { - return; - } - field.setContent(content[title]); - }); - - 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; - } - const templatefieldID = templateField.getID; - - return this.renderGPTTextCall(templateCopy, field, templatefieldID); - }); + const templateCopy = await template.cloneBase(); - 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; - } - const templatefieldID = templateField.getID; - - return this.renderGPTImageCall(templateCopy, field, templatefieldID); - }); + fields.filter(title => title).forEach(title => { + const field = templateCopy.getFieldByTitle(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; + const templatefieldID = templateField.getID; + + return this.renderGPTTextCall(templateCopy, field, templatefieldID); + }); + 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; + const templatefieldID = templateField.getID; + + return this.renderGPTImageCall(templateCopy, field, templatefieldID); + }); + await Promise.all(gptPromises); await Promise.all(imagePromises); - return templateCopy.getRenderedDoc(); + this._DOCCC = templateCopy.mainField.renderedDoc; + return templateCopy.mainField.renderedDoc; }; + + let docs: Promise<Doc>[]; + if (this.DEBUG_MODE) { + docs = [1, 2, 3, 4].map(() => processContent({})); + } else { + docs = rowContents.map(content => processContent(content)); + } - const promises = rowContents.map(content => processContent(content)); - - const renderedDocs = await Promise.all(promises); + const renderedDocs = await Promise.all(docs); - this._docsRendering = false; + this._docsRendering = false; // removes loading indicator return renderedDocs; - }; + } addRenderedCollectionToMainview = () => { const collection = this._renderedDocCollection; @@ -760,7 +795,7 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps> @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; @@ -799,24 +834,16 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps> <div className="top-panel" /> {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); - }) - }> + <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.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); - }) - }> + <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> @@ -825,8 +852,36 @@ 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} + // 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 ( <div className={`docCreatorMenu-templates-view`}> {this._expandedPreview ? ( @@ -846,51 +901,30 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps> <ReactLoading type="spin" color={StrCast(Doc.UserDoc().userVariantColor)} height={30} width={30} /> </div> ) : ( - this._suggestedTemplatePreviews.map(({ doc, template }) => ( - <div - className="docCreatorMenu-preview-window" - key="0" - style={{ - border: this._selectedTemplate === template ? `solid 3px ${Colors.MEDIUM_BLUE}` : '', - boxShadow: this._selectedTemplate === template ? `0 0 15px rgba(68, 118, 247, .8)` : '', - }} - onPointerDown={e => this.setUpButtonClick(e, () => runInAction(() => this.updateSelectedTemplate(template)))}> - <button - className="option-button left" - onPointerDown={e => - this.setUpButtonClick(e, () => { - this.setExpandedView(template); - }) - }> - <FontAwesomeIcon icon="magnifying-glass" color="white" /> - </button> - <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} - pinToPres={() => undefined} - childFilters={returnEmptyFilter} - childFiltersByRanges={returnEmptyFilter} - searchFilterDocs={returnEmptyDoclist} - fitContentsToBox={returnFalse} - fitWidth={returnFalse} - hideDecorations={true} - /> - </div> - )) + this._suggestedTemplates + .map(template => ( + <div + className="docCreatorMenu-preview-window" + style={{ + border: this._selectedTemplate === template ? `solid 3px ${Colors.MEDIUM_BLUE}` : '', + boxShadow: this._selectedTemplate === template ? `0 0 15px rgba(68, 118, 247, .8)` : '', + }} + onPointerDown={e => this.setUpButtonClick(e, () => runInAction(() => this.updateSelectedTemplate(template)))}> + <button + className="option-button left" + onPointerDown={e => + this.setUpButtonClick(e, () => { + this.setExpandedView(template); + }) + }> + <FontAwesomeIcon icon="magnifying-glass" color="white" /> + </button> + <button className="option-button right" onPointerDown={e => this.setUpButtonClick(e, () => this.addUserTemplate(template))}> + <FontAwesomeIcon icon="plus" color="white" /> + </button> + {previewDoc(template.getRenderedDoc(), template)} + </div> + )) )} </div> <div className="docCreatorMenu-GPT-options"> @@ -914,51 +948,30 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps> <div className="docCreatorMenu-preview-window empty"> <FontAwesomeIcon icon="plus" color="rgb(160, 160, 160)" /> </div> - {this._userTemplates.map(({ template, doc }) => ( - <div - className="docCreatorMenu-preview-window" - key="0" - style={{ - border: this._selectedTemplate === template ? `solid 3px ${Colors.MEDIUM_BLUE}` : '', - boxShadow: this._selectedTemplate === template ? `0 0 15px rgba(68, 118, 247, .8)` : '', - }} - onPointerDown={e => this.setUpButtonClick(e, () => runInAction(() => this.updateSelectedTemplate(template)))}> - <button - className="option-button left" - onPointerDown={e => - this.setUpButtonClick(e, () => { - this.setExpandedView(template); - }) - }> - <FontAwesomeIcon icon="magnifying-glass" color="white" /> - </button> - <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} - pinToPres={() => undefined} - childFilters={returnEmptyFilter} - childFiltersByRanges={returnEmptyFilter} - searchFilterDocs={returnEmptyDoclist} - fitContentsToBox={returnFalse} - fitWidth={returnFalse} - hideDecorations={true} - /> - </div> - ))} + {this._userTemplates + .map(template => ( + <div + className="docCreatorMenu-preview-window" + style={{ + border: this._selectedTemplate === template ? `solid 3px ${Colors.MEDIUM_BLUE}` : '', + boxShadow: this._selectedTemplate === template ? `0 0 15px rgba(68, 118, 247, .8)` : '', + }} + onPointerDown={e => this.setUpButtonClick(e, () => runInAction(() => this.updateSelectedTemplate(template)))}> + <button + className="option-button left" + onPointerDown={e => + this.setUpButtonClick(e, () => { + this.setExpandedView(template); + }) + }> + <FontAwesomeIcon icon="magnifying-glass" color="white" /> + </button> + <button className="option-button right" onPointerDown={e => this.setUpButtonClick(e, () => this.removeUserTemplate(template))}> + <FontAwesomeIcon icon="minus" color="white" /> + </button> + {previewDoc(template.getRenderedDoc(), template)} + </div> + ))} </div> </div> </div> @@ -1017,13 +1030,11 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps> 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 startX: number = -Number(collection._width) / 2; - const startY: number = -Number(collection._height) / 2; + 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); const docWidth: number = Number(docs[0]._width); @@ -1070,8 +1081,6 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps> updateRenderedDocCollection = () => { if (!this._fullyRenderedDocs) return; - const { horizontalSpan, verticalSpan } = this.previewInfo; - const collectionFactory = (): ((docs: Doc[], options: DocumentOptions) => Doc) => { switch (this._layout.type) { case LayoutType.CAROUSEL3D: @@ -1089,18 +1098,25 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps> } }; - const collection: Doc = collectionFactory()(this._fullyRenderedDocs, { + const collection = collectionFactory()([this._fullyRenderedDocs[6], this._fullyRenderedDocs[9]], { isDefaultTemplateDoc: true, - _height: verticalSpan, - _width: horizontalSpan, title: 'title', backgroundColor: 'gray', + x: 200, + y: 200, + _width: 4000, + _height: 4000, }); this.applyLayout(collection, this._fullyRenderedDocs); this._renderedDocCollection = collection; - }; + + const mainCollection = this._dataViz?.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionFreeFormView; + mainCollection.addDocument(collection); + + console.log('changed to: ', collection); + } layoutPreviewContents = () => { return this._docsRendering ? ( @@ -1109,7 +1125,7 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps> <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"> <DocumentView Document={this._renderedDocCollection} 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..62f5504a8 --- /dev/null +++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DecorationField.tsx @@ -0,0 +1,35 @@ +import { Doc, DocListCast } from "../../../../../../fields/Doc"; +import { Docs, DocumentOptions } from "../../../../../documents/Documents"; +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 Document: Doc; + + constructor(settings: FieldSettings, id: number, parent: Field) { + super(settings, id, FieldUtils.initField, parent); + this.subfields = this.setupSubfields(this); + this.Document = this.initializeDocument(); + }; + + setContent = (content: string, type?: ViewType) => { return } + getContent = () => { return 'none'}; + get isContentField(): boolean { return false }; + + initializeDocument = (): Doc => { + const renderedSubfields: Doc[] = this.subfields.map(field => field.renderedDoc); + this.settings.opts.title = this.title; + let doc: Doc = Docs.Create.FreeformDocument(renderedSubfields, this.settings.opts); + + this.Document = 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 c5254c17d..1970d1557 100644 --- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx +++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx @@ -1,117 +1,117 @@ -import { Doc } from "../../../../../../fields/Doc"; -import { Docs } from "../../../../../documents/Documents"; +import { makeAutoObservable, makeObservable, reaction } from "mobx"; +import { Doc, DocListCast } from "../../../../../../fields/Doc"; +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 { StaticField } from "./StaticField"; +import { random } from "lodash"; -export class DynamicField implements Field { - private subfields: Field[] = []; +export class DynamicField extends Field { + protected subfields: Field[]; - private id: number; - private settings: FieldSettings; - private title: string = ''; + protected Document!: Doc; - private parent: Field; - private dimensions: FieldDimensions; + private idd: number; constructor(settings: FieldSettings, id: number, parent?: Field) { - 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]}}; - } else { - this.parent = parent; - this.dimensions = FieldUtils.getLocalDimensions({tl: settings.tl, br: settings.br}, this.parent.getDimensions); - } - this.subfields = this.setupSubfields(); + super(settings, id, FieldUtils.initField, parent); + this.subfields = this.setupSubfields(this); + this.initializeDocument(); + this.idd = random(0, 1000); } - setContent = () => { return }; + setContent = (content: string, type: ViewType) => { return }; getContent = () => { return '' }; + get isContentField(): boolean { return false }; - setTitle = (title: string) => { this.title = title }; - getTitle = () => { return this.title }; - - 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 ?? ''; + addChildToDocument = (doc: Doc) => { + Doc.SetContainer(doc, this.Document); } matches = (): 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; + 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 } - 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 - 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 }; - }; - - renderedDoc = (): Doc => { + 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: - doc = Docs.Create.Carousel3DDocument(this.subfields.map(field => field.renderedDoc()), { - title: this.title, - }); - FieldUtils.applyBasicOpts(doc, this.dimensions, this.settings); - return doc; + doc = Docs.Create.Carousel3DDocument(renderedSubfields, this.settings.opts); + break; case ViewType.FREEFORM: - doc = Docs.Create.FreeformDocument(this.subfields.map(field => field.renderedDoc()), { - title: this.title, - }); - FieldUtils.applyBasicOpts(doc, this.dimensions, this.settings); - return doc; + doc = Docs.Create.FreeformDocument(renderedSubfields, oldOpts ?? this.settings.opts); + break; default: - return new Doc(); + doc = Docs.Create.FreeformDocument(renderedSubfields, this.settings.opts); + break; } + + 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 ea9b566b3..06b364254 100644 --- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx +++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx @@ -1,44 +1,232 @@ -import { Doc } from "../../../../../../fields/Doc"; +import { computed, makeAutoObservable, makeObservable, reaction } from "mobx"; +import { Doc, DocListCast } from "../../../../../../fields/Doc"; 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"; +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"; +import { OmitKeys } from "../../../../../../ClientUtils"; -export enum FieldContentType { - STRING = 'string', - IMAGE = 'image', -} +export abstract class Field { -export enum ViewType { - CAROUSEL3D = 'carousel3d', - FREEFORM = 'freeform', - STATIC = 'static', - DEC = 'decoration' -} + protected disposers: { [name: string]: IDisposer } = {}; + + protected initField: (settings: FieldSettings, index: number, parent: Field, sameId?: boolean) => Field; -export type FieldDimensions = { - width: number; - height: number; - coord: {x: number, y: number}; -} + protected abstract subfields: Field[]; + + protected abstract Document: Doc; + + protected parent: Field; + protected id: number; + protected settings: FieldSettings; + protected title: string = ''; + protected dimensions: FieldDimensions; + + constructor(settings: FieldSettings, id: number, fieldFactory: (settings: FieldSettings, index: number, parent: Field) => Field, parent?: Field) { + this.initField = fieldFactory; + this.parent = parent ? parent : this; + 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.Document[Doc.LayoutFieldKey(this.Document)]), + // docs => { + // console.log('updated') + // this.handleFieldUpdate(docs); + // } + // ); + } + + 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; + }; + + setSubFields = (fields: Field[]) => { + this.subfields = fields; + } + + 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; + + makeClone = async (subfields: boolean = false): Promise<Field> => { + const newSettings: FieldSettings = this.settings; + if (!subfields) newSettings.subfields = []; + newSettings.opts = this.documentOptions; + 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 { + 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 => { + const newField: Field = this.initField(this.settings, this.id, this.parent, true); + this.parent.exchangeFields(newField, this); + return newField; + } + + exchangeFields = (newField: Field, oldField: Field) => { + this.subfields.splice(this.subfields.indexOf(oldField), 1, newField); + } + + 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 = this.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); + } + } + + 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.dispose(); + }; + + setupSubfields = (parent: Field): Field[] => { + return this.settings.subfields?.map((fieldSettings, index) => { + return this.initField(fieldSettings, index, parent); + }) || []; + } + + applyAttributes(field: Field) { + field.setTitle(this.title); + field.initializeDocument(); + field.subfields = this.subfields; + } + + abstract initializeDocument(): void; + + dispose = () => { + Object.values(this.disposers).forEach(disposer => disposer?.()); + } + + 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)); + } + }); + } + + 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 (this.parent === this) { + 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 interface FieldOpts { - backgroundColor?: string; - color?: string; - cornerRounding?: number; - borderWidth?: string; - borderColor?: string; - contentXCentering?: 'h-left' | 'h-center' | 'h-right'; - contentYCentering?: 'top' | 'center' | 'bottom'; - opacity?: number; - rotation?: number; - fontBold?: boolean; - fontTransform?: 'uppercase' | 'lowercase'; - fieldViewType?: 'freeform' | 'stacked'; } export type FieldSettings = { tl: [number, number]; br: [number, number]; - opts: FieldOpts; + opts: DocumentOptions; viewType: ViewType; title?: string; subfields?: FieldSettings[]; @@ -47,20 +235,21 @@ export type FieldSettings = { description?: string; }; -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) => Doc; -}
\ No newline at end of file +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 index 3886774d2..eb12bfef9 100644 --- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx +++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx @@ -1,40 +1,24 @@ -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, 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 => { - 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 }; - }; - 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.cornerRounding ? '0px' : ScriptField.MakeFunction(`${opts.cornerRounding} * 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.contentXCentering; - doc.nativeWidth = parentDimensions.width; - doc.nativeHeight = parentDimensions.height; - doc._layout_nativeDimEditable = true; - }; + 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); + case ViewType.IMG: + return new ImageTemplateField(settings, id, parent); + case ViewType.TEXT: + return new TextTemplateField(settings, id, parent); + case ViewType.DEC: + return new DecorationField(settings, id, parent); + } + return new TextTemplateField(settings, id, parent); + } 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 new file mode 100644 index 000000000..18b72e4ea --- /dev/null +++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticContentField.tsx @@ -0,0 +1,104 @@ +import { Doc, DocListCast } from "../../../../../../fields/Doc"; +import { Docs, DocumentOptions } from "../../../../../documents/Documents"; +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"; +import { random } from "lodash"; + +export abstract class StaticContentField extends Field { + + protected content: string = ''; + protected subfields: 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; + getContent = () => { return this.content ?? 'unset'}; + get isContentField(): boolean { return true }; + + abstract initializeDocument(): Doc; +} + +export class ImageTemplateField extends StaticContentField { + + 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(): Doc { + this.settings.opts.title = this.title; + this.settings.opts._layout_fitWidth = false; + + let doc: Doc = Docs.Create.ImageDocument(this.content, this.settings.opts); + + return doc; + }; +} + +export class TextTemplateField extends StaticContentField { + + 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(): Doc { + const opts = this.settings.opts; + 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); + + 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 47b43f051..000000000 --- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx +++ /dev/null @@ -1,147 +0,0 @@ -import { Doc } from "../../../../../../fields/Doc"; -import { Docs } from "../../../../../documents/Documents"; -import { Col } from "../DocCreatorMenu"; -import { DynamicField } from "./DynamicField"; -import { FieldUtils } from "./FieldUtils"; -import { Field, FieldContentType, FieldDimensions, FieldSettings, ViewType } from "./Field"; - -export class StaticField { - private content: string; - private contentType: FieldContentType | undefined; - private subfields: Field[] = []; - private renderedDocument: Doc; - - private id: number; - private title: string = ''; - - private settings: FieldSettings; - - private parent: Field; - private dimensions: FieldDimensions; - - constructor(settings: FieldSettings, parent: Field, id: number) { - this.settings = settings; - if (settings.title) { this.title = settings.title }; - this.id = id; - 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(); - }; - - 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 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; - this.updateRenderedDoc(this.renderedDocument); - }; - getContent() { return this.content }; - - setTitle = (title: string) => { - this.title = title; - this.renderedDocument.title = title; - this.updateRenderedDoc(this.renderedDocument); - }; - 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); - field.setContent('', this.contentType); - field.updateRenderedDoc(this.renderedDoc()); - } - - 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.FREEFORM || type === ViewType.CAROUSEL3D) { - field = new DynamicField(fieldSettings, id, this); - } else { - field = new StaticField(fieldSettings, this, id); - }; - - fields.push(field); - }); - return fields; - }; - - 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: - doc = Docs.Create.TextDocument(String(this.content), { - title: this.title, - text_fontColor: oldDoc ? String(oldDoc.color) : opts.color, - contentBold: oldDoc ? Boolean(oldDoc.fontBold) : opts.fontBold, - textTransform: oldDoc ? String(oldDoc.fontTransform) : opts.fontTransform, - color: oldDoc ? String(oldDoc.color) : opts.color, - _text_fontSize: `${FieldUtils.calculateFontSize(this.dimensions.width, this.dimensions.height, String(this.content), true)}` - }); - FieldUtils.applyBasicOpts(doc, this.dimensions, this.settings, oldDoc); - break; - case FieldContentType.IMAGE: - doc = Docs.Create.ImageDocument(String(this.content), { - title: this.title, - _layout_fitWidth: false, - }); - FieldUtils.applyBasicOpts(doc, this.dimensions, this.settings, oldDoc); - break; - } - - 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 0a5097d4a..bdfedbdc9 100644 --- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx +++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx @@ -1,43 +1,64 @@ 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, ViewType } from "./FieldTypes/Field"; +import { Field, FieldSettings, FieldTree, ViewType } from "./FieldTypes/Field"; import { } from "./FieldTypes/FieldUtils"; import { } from "./FieldTypes/StaticField"; +import { TemplateLayouts } from "./TemplateBackend"; export class Template { mainField: DynamicField; - settings: FieldSettings; + private settings: FieldSettings; constructor(templateInfo: FieldSettings) { - this.mainField = this.setupMainField(templateInfo); + 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.getViewType === ViewType.STATIC) }; - get doc(){ return this.mainField.renderedDoc(); }; - - cloneBase = () => { - const clone: Template = new Template(this.settings); - clone.allFields.forEach(field => { - const matchingField: Field = this.allFields.filter(f => f.getID === field.getID)[0]; - matchingField.applyAttributes(field); - }) + 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 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); + 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; } - getRenderedDoc = () => { - const doc: Doc = this.mainField.renderedDoc(); - 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 => { @@ -68,21 +89,16 @@ export class Template { return summary; } - renderUpdates = () => { - this.allFields.forEach(field => { - field.updateRenderedDoc(field.renderedDoc()); - }); - }; - resetToBase = () => { this.allFields.forEach(field => { - field.updateRenderedDoc(); + field.initializeDocument(); }) } 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/TemplateBackend.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx index d3282eda3..2b32d49aa 100644 --- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx +++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx @@ -1,5 +1,4 @@ import { FieldSettings, ViewType } from "./FieldTypes/Field"; -import { } from "./FieldTypes/StaticField"; export enum TemplateFieldType { TEXT = 'text', @@ -20,6 +19,14 @@ export class TemplateLayouts { 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], @@ -27,7 +34,7 @@ export class TemplateLayouts { viewType: ViewType.FREEFORM, opts: { backgroundColor: '#C0B887', - cornerRounding: .05, + _layout_borderRounding: '.05', //borderColor: '#6B461F', //borderWidth: '12', }, @@ -41,9 +48,9 @@ export class TemplateLayouts { description: 'A title field for very short text that contextualizes the content.', opts: { backgroundColor: 'transparent', - color: '#F1F0E9', - contentXCentering: 'h-center', - fontBold: true, + text_fontColor: '#F1F0E9', + hCentering: 'h-center', + contentBold: true, }, }, { @@ -54,9 +61,9 @@ 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: { - cornerRounding: .05, + _layout_borderRounding: '.05', borderColor: '#8F5B25', - borderWidth: '6', + borderWidth: 6, backgroundColor: '#CECAB9', }, }, @@ -69,8 +76,8 @@ export class TemplateLayouts { description: 'A caption for field #2, very short text.', opts: { backgroundColor: 'transparent', - contentXCentering: 'h-center', - color: '#F1F0E9', + hCentering: 'h-center', + text_fontColor: '#F1F0E9', }, }, { @@ -81,9 +88,9 @@ export class TemplateLayouts { sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE], description: 'A medium-sized field for medium/long text.', opts: { - cornerRounding: .05, + _layout_borderRounding: '.05', borderColor: '#8F5B25', - borderWidth: '6', + borderWidth: 6, backgroundColor: '#CECAB9', }, }, @@ -107,10 +114,10 @@ export class TemplateLayouts { 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', + borderWidth: 8, borderColor: '#F8E71C', backgroundColor: '#242425', - color: 'white', + text_fontColor: 'white', }, }, { @@ -122,9 +129,9 @@ export class TemplateLayouts { description: 'A tiny field for just a word or two of plain text.', opts: { backgroundColor: 'transparent', - color: 'white', - contentXCentering: 'h-center', - fontTransform: 'uppercase', + text_fontColor: 'white', + hCentering: 'h-center', + text_transform: 'uppercase', }, }, { @@ -136,9 +143,9 @@ export class TemplateLayouts { description: 'A tiny field for just a word or two of plain text.', opts: { backgroundColor: 'transparent', - color: 'white', - contentXCentering: 'h-center', - fontTransform: 'uppercase', + text_fontColor: 'white', + hCentering: 'h-center', + text_transform: 'uppercase', }, }, { @@ -149,9 +156,9 @@ export class TemplateLayouts { 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', + borderWidth: 8, borderColor: '#F8E71C', - color: 'white', + text_fontColor: 'white', backgroundColor: '#242425', }, }, @@ -161,7 +168,7 @@ export class TemplateLayouts { br: [-0.525, 0.075], opts: { backgroundColor: '#F8E71C', - rotation: 45, + _rotation: 45, }, }, { @@ -170,7 +177,7 @@ export class TemplateLayouts { br: [-0.2175, 0.0245], opts: { backgroundColor: '#F8E71C', - rotation: 45, + _rotation: 45, }, }, { @@ -179,7 +186,7 @@ export class TemplateLayouts { br: [0.045, 0.0245], opts: { backgroundColor: '#F8E71C', - rotation: 45, + _rotation: 45, }, }, { @@ -188,7 +195,7 @@ export class TemplateLayouts { br: [0.3075, 0.0245], opts: { backgroundColor: '#F8E71C', - rotation: 45, + _rotation: 45, }, }, { @@ -197,7 +204,7 @@ export class TemplateLayouts { br: [0.8, 0.075], opts: { backgroundColor: '#F8E71C', - rotation: 45, + _rotation: 45, }, }, ], @@ -283,9 +290,9 @@ export class TemplateLayouts { description: 'A tiny field for just a word or two of plain text.', opts: { backgroundColor: '#E2B4F5', - borderWidth: '9', + borderWidth: 9, borderColor: '#9222F1', - contentXCentering: 'h-center', + hCentering: 'h-center', }, }, { @@ -297,9 +304,9 @@ export class TemplateLayouts { description: 'A tiny field for just a word or two of plain text.', opts: { backgroundColor: '#F5B4DD', - borderWidth: '9', + borderWidth: 9, borderColor: '#E260F3', - contentXCentering: 'h-center', + hCentering: 'h-center', }, }, { @@ -310,7 +317,7 @@ export class TemplateLayouts { 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', + borderWidth: 16, borderColor: '#A2BD77', }, }, @@ -322,7 +329,7 @@ export class TemplateLayouts { sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE], description: 'A medium to large field for text that describes the visual content above', opts: { - borderWidth: '9', + borderWidth: 9, borderColor: '#F0D601', backgroundColor: '#F3F57D', }, @@ -334,7 +341,7 @@ export class TemplateLayouts { opts: { backgroundColor: 'transparent', borderColor: '#007C0C', - borderWidth: '10', + borderWidth: 10, }, }, ], @@ -358,8 +365,8 @@ export class TemplateLayouts { description: 'A small text field for a title or word(s) that categorize the rest of the content.', opts: { borderColor: '#3B4A2C', - borderWidth: '8', - contentXCentering: "h-center", + borderWidth: 8, + hCentering: "h-center", backgroundColor: '#B8DC90', }, }, @@ -372,8 +379,8 @@ export class TemplateLayouts { description: 'A small text field for a title that categorizes the rest of the content.', opts: { borderColor: '#3B4A2C', - borderWidth: '8', - contentXCentering: "h-center", + borderWidth: 8, + hCentering: "h-center", backgroundColor: '#B8DC90', }, }, @@ -384,7 +391,7 @@ export class TemplateLayouts { opts: { backgroundColor: '#94B058', borderColor: '#3B4A2C', - borderWidth: '8', + borderWidth: 8, }, }, { @@ -396,7 +403,7 @@ export class TemplateLayouts { description: 'A medium to large field in the center of the template, for the main visual content.', opts: { borderColor: '#3B4A2C', - borderWidth: '8', + borderWidth: 8, backgroundColor: '#B8DC90', }, }, @@ -409,8 +416,8 @@ export class TemplateLayouts { description: 'A medium to large field at the bottom of the template, for the main text content.', opts: { borderColor: '#3B4A2C', - borderWidth: '8', - contentXCentering: "h-center", + borderWidth: 8, + hCentering: "h-center", backgroundColor: '#B8DC90', }, }, @@ -421,7 +428,7 @@ export class TemplateLayouts { opts: { backgroundColor: '#7A9D31', borderColor: '#3B4A2C', - borderWidth: '8', + borderWidth: 8, }, }, { @@ -431,7 +438,7 @@ export class TemplateLayouts { opts: { backgroundColor: '#94B058', borderColor: '#3B4A2C', - borderWidth: '8', + borderWidth: 8, }, }, { @@ -441,7 +448,7 @@ export class TemplateLayouts { opts: { backgroundColor: '#728745', borderColor: '#3B4A2C', - borderWidth: '8', + borderWidth: 8, }, }, { @@ -451,7 +458,7 @@ export class TemplateLayouts { opts: { backgroundColor: '#7A9D31', borderColor: '#3B4A2C', - borderWidth: '8', + borderWidth: 8, }, }, { @@ -461,7 +468,7 @@ export class TemplateLayouts { opts: { backgroundColor: '#728745', borderColor: '#3B4A2C', - borderWidth: '8', + borderWidth: 8, }, }, { @@ -471,7 +478,7 @@ export class TemplateLayouts { opts: { backgroundColor: '#94B058', borderColor: '#3B4A2C', - borderWidth: '8', + borderWidth: 8, }, }, ] @@ -483,7 +490,7 @@ export class TemplateLayouts { tl:[0,0], br:[500, 600], opts: { - backgroundColor: '#DDD3A9', + backgroundColor: '#D7CBAB', }, subfields: [ { @@ -494,63 +501,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', - contentXCentering: "h-center", + hCentering: "h-center", backgroundColor: 'transparent', + text_transform: 'uppercase', }, }, { viewType: ViewType.CAROUSEL3D, - tl: [-0.9, -.3], - br: [0.9, .9], + tl: [-0.9, -.5], + br: [0.9, .25], opts: { - borderColor: 'yellow', - borderWidth: '8', - backgroundColor: 'transparent', + borderColor: '#847F69', + borderWidth: 8, + 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, @@ -567,9 +586,9 @@ export class TemplateLayouts { description: 'A medium to large field for visual content that is the central focus.', opts: { borderColor: 'yellow', - borderWidth: '8', + borderWidth: 8, backgroundColor: '#DDD3A9', - rotation: 45, + _rotation: 45, }, subfields: [ { @@ -580,7 +599,7 @@ export class TemplateLayouts { sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE], description: 'A medium to large field for visual content that is the central focus.', opts: { - rotation: -45, + _rotation: -45, }, }, ] @@ -594,7 +613,7 @@ export class TemplateLayouts { description: 'A very small text field for one to a few words. A good caption for the image.', opts: { backgroundColor: 'transparent', - contentXCentering: 'h-center', + hCentering: 'h-center', }, }, { @@ -606,7 +625,7 @@ export class TemplateLayouts { description: 'A medium to large text field for a thorough description of the image. ', opts: { backgroundColor: 'transparent', - color: 'white', + text_fontColor: 'white', }, }, { @@ -615,7 +634,7 @@ export class TemplateLayouts { br: [1.8, -0.66], opts: { backgroundColor: '#CEB155', - rotation: 45, + _rotation: 45, }, subfields: [ { @@ -634,7 +653,7 @@ export class TemplateLayouts { br: [-0.2, -0.66], opts: { backgroundColor: '#CEB155', - rotation: 135, + _rotation: 135, }, subfields: [ { @@ -653,7 +672,7 @@ export class TemplateLayouts { br: [1.66, 1.25], opts: { backgroundColor: '#CEB155', - rotation: 135, + _rotation: 135, }, subfields: [ { @@ -672,7 +691,7 @@ export class TemplateLayouts { br: [-0.33, 1.25], opts: { backgroundColor: '#CEB155', - rotation: 45, + _rotation: 45, }, subfields: [ { @@ -705,7 +724,7 @@ export class TemplateLayouts { sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE], description: 'A medium to large visual field for the main content of the template', opts: { - borderWidth: '15', + borderWidth: 15, borderColor: '#E0E0DA', }, }, @@ -718,10 +737,10 @@ export class TemplateLayouts { 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', - color: '#AF0D0D', - fontTransform: 'uppercase', - fontBold: true, - contentXCentering: 'h-left', + text_fontColor: '#AF0D0D', + text_transform: 'uppercase', + contentBold: true, + hCentering: 'h-left', }, }, { @@ -733,8 +752,8 @@ export class TemplateLayouts { description: 'A very small text field for one to a few words. The content should contextualize field 2.', opts: { backgroundColor: 'transparent', - color: 'black', - contentXCentering: 'h-right', + text_fontColor: 'black', + hCentering: 'h-right', }, }, { diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.tsx index 50ae4d72a..09b4ce029 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"; @@ -7,6 +8,7 @@ export class TemplateManager { templates: Template[] = []; constructor(templateSettings: FieldSettings[]) { + makeAutoObservable(this); this.templates = this.initializeTemplates(templateSettings); } @@ -17,6 +19,16 @@ export class TemplateManager { } 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 diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index fc89dcbe7..bb7df75fc 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -573,7 +573,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; } |